QT Widgets界面编程实战技巧

QT Widgets界面编程实战技巧
使用AI技术辅助生成

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

1 QT_Widgets界面布局与设计

1.1 1_1_界面布局策略

1.1.1 1_1_界面布局策略

1_1_界面布局策略
1_1_界面布局策略
在QT Widgets应用程序中,界面布局是指将控件组织在窗口或容器中的过程。一个良好的界面布局不仅可以让应用程序看起来更加美观和专业,还可以提高用户的使用体验。QT提供了多种布局策略,本节将介绍一些常用的布局策略。

  1. 线性布局
    线性布局(QHBoxLayout和QVBoxLayout)是将控件按照垂直或水平方向依次排列的布局。这种布局方式简单易懂,适用于将几个控件排列成一行或一列的情况。
    cpp
    QHBoxLayout *horizontalLayout = new QHBoxLayout();
    horizontalLayout->addWidget(button1);
    horizontalLayout->addWidget(button2);
    horizontalLayout->addWidget(button3);
    QVBoxLayout *verticalLayout = new QVBoxLayout();
    verticalLayout->addLayout(horizontalLayout);
    verticalLayout->addWidget(label);
  2. 网格布局
    网格布局(QGridLayout)可以将控件按照网格形式排列,每个控件占据一个网格单元。这种布局方式灵活且易于控制,适用于需要将多个控件按照行列排列的情况。
    cpp
    QGridLayout *gridLayout = new QGridLayout();
    gridLayout->addWidget(button1, 0, 0);
    gridLayout->addWidget(button2, 0, 1);
    gridLayout->addWidget(button3, 0, 2);
    gridLayout->addWidget(label, 1, 0);
  3. 栈布局
    栈布局(QStackedLayout)可以将多个布局堆叠在一起,通过切换不同的布局来实现不同的界面显示。这种布局方式适用于需要根据不同情况切换界面布局的情况。
    cpp
    QStackedLayout *stackedLayout = new QStackedLayout();
    stackedLayout->addLayout(horizontalLayout);
    stackedLayout->addLayout(verticalLayout);
  4. 框布局
    框布局(QFormLayout)可以按照表单的形式排列控件,每个控件占据一行。这种布局方式适用于创建表单风格的界面。
    cpp
    QFormLayout *formLayout = new QFormLayout();
    formLayout->addRow(tr(Label:), lineEdit);
    formLayout->addRow(tr(Password:), passwordLineEdit);
  5. 空间布局
    空间布局(QSpacerItem)可以用来在布局中创建空白空间,用于填充或间隔其他控件。
    cpp
    QSpacerItem *horizontalSpacer = new QSpacerItem(10, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    horizontalLayout->addItem(horizontalSpacer);
    在实际开发中,可以根据具体需求和场景选择合适的布局策略。此外,QT还提供了其他一些布局策略,如标签布局、对话框布局等,可以根据需要进行选择和定制。

1.2 1_2_高级布局管理技巧

1.2.1 1_2_高级布局管理技巧

1_2_高级布局管理技巧
1_2_高级布局管理技巧
在QT Widgets应用程序中,布局管理是控制控件位置和大小的重要组成部分。QT提供了多种布局管理器,如QHBoxLayout、QVBoxLayout、QGridLayout和QFormLayout等,它们能帮助我们对控件进行灵活的布局管理。但在实际开发过程中,我们有时会遇到一些复杂的情况,需要进行更高级的布局管理。本节将介绍一些高级布局管理的技巧。

  1. 使用布局嵌套
    在某些复杂的界面设计中,我们可能需要将多种布局管理器进行嵌套使用,以达到理想的布局效果。例如,我们可以在一个QVBoxLayout中嵌入一个QGridLayout,或者在一个QHBoxLayout中嵌套使用QVBoxLayout。
    cpp
    QVBoxLayout *mainLayout = new QVBoxLayout();
    QHBoxLayout *horizontalLayout = new QHBoxLayout();
    QGridLayout *gridLayout = new QGridLayout();
    __ 在主布局中嵌入水平布局
    mainLayout->addLayout(horizontalLayout);
    __ 在水平布局中嵌入网格布局
    horizontalLayout->addLayout(gridLayout);
    __ 设置控件
    QPushButton *button1 = new QPushButton(按钮1);
    QPushButton *button2 = new QPushButton(按钮2);
    QPushButton *button3 = new QPushButton(按钮3);
    gridLayout->addWidget(button1, 0, 0);
    gridLayout->addWidget(button2, 0, 1);
    gridLayout->addWidget(button3, 0, 2);
    __ 设置主窗口的布局
    this->setLayout(mainLayout);
  2. 控制控件的间距
    在布局中,控件与控件之间、控件与边框之间的间距对于界面的美观和易用性非常重要。我们可以使用setSpacing()方法来设置布局中所有控件之间的间距,也可以使用setContentsMargins()方法来设置布局内容的内边距。
    cpp
    __ 设置布局的间距
    mainLayout->setSpacing(10);
    __ 设置布局的内边距
    mainLayout->setContentsMargins(20, 30, 40, 50);
  3. 使用间距布局
    QT提供了一种特殊的布局管理器——QSpacerItem,它可以作为一个控件来使用,用于在布局中占据一定的空间,常用于调整布局间距。
    cpp
    QSpacerItem *horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    __ 将占位符添加到水平布局中
    horizontalLayout->addItem(horizontalSpacer);
  4. 动态调整布局
    在某些情况下,我们需要根据窗口的大小或内容的变动来动态调整布局。可以使用布局管理器的setGeometry()方法来设置布局的大小,也可以通过监听窗口大小改变事件或布局中的控件变化来调整布局。
    cpp
    __ 监听窗口大小改变事件
    this->resizeEvent([=](QResizeEvent *event){
    __ 根据窗口大小调整布局
    });
    __ 监听控件的更改事件
    connect(button1, &QPushButton::clicked, [=]{
    __ 根据控件状态调整布局
    });
    通过以上技巧,我们可以更灵活地进行高级布局管理,创造出既美观又实用的界面。

1.3 1_3_界面元素对齐与间距控制

1.3.1 1_3_界面元素对齐与间距控制

1_3_界面元素对齐与间距控制
1_3_界面元素对齐与间距控制
在QT Widgets界面编程中,界面元素的布局和间距对于创建美观和易于使用的用户界面至关重要。QT提供了多种布局管理器来实现这一目标,如QHBoxLayout、QVBoxLayout、QGridLayout等,以及弹性布局QBoxLayout。本节将介绍如何使用这些布局管理器对齐界面元素以及如何控制它们之间的间距。

  1. 对齐界面元素
    使用QHBoxLayout水平布局
    当您希望将多个控件水平排列时,可以使用QHBoxLayout。这是一个例子,
    cpp
    QHBoxLayout *horizontalLayout = new QHBoxLayout();
    horizontalLayout->addWidget(new QPushButton(按钮1));
    horizontalLayout->addWidget(new QPushButton(按钮2));
    horizontalLayout->addWidget(new QPushButton(按钮3));
    使用QVBoxLayout垂直布局
    若需要将控件垂直排列,QVBoxLayout是理想的选择,
    cpp
    QVBoxLayout *verticalLayout = new QVBoxLayout();
    verticalLayout->addWidget(new QPushButton(按钮1));
    verticalLayout->addWidget(new QPushButton(按钮2));
    verticalLayout->addWidget(new QPushButton(按钮3));
    使用QGridLayout网格布局
    当您需要更复杂的布局,如同时控制行和列时,QGridLayout会很有帮助,
    cpp
    QGridLayout *gridLayout = new QGridLayout();
    gridLayout->addWidget(new QPushButton(按钮1), 0, 0);
    gridLayout->addWidget(new QPushButton(按钮2), 0, 1);
    gridLayout->addWidget(new QPushButton(按钮3), 1, 0);
    使用QBoxLayout弹性布局
    QBoxLayout可以看作是QHBoxLayout和QVBoxLayout的结合体,它可以很方便地对齐和分布对齐方向上的控件,
    cpp
    QBoxLayout *boxLayout = new QBoxLayout(QBoxLayout::RightToLeft); __ 右到左排列
    boxLayout->addWidget(new QPushButton(按钮1));
    boxLayout->addWidget(new QPushButton(按钮2));
    boxLayout->addWidget(new QPushButton(按钮3));
  2. 控制界面元素间距
    在QT中,您可以使用布局管理器的间距函数来调整控件之间的间距,
    设置QSpacing
    QSpacing类定义了间距的类型,提供了便利的函数来设置间距,
    cpp
    QSpacing horizontalSpacing(10); __ 水平间距为10像素
    QSpacing verticalSpacing(15); __ 垂直间距为15像素
    horizontalLayout->setSpacing(horizontalSpacing);
    verticalLayout->setSpacing(verticalSpacing);
    gridLayout->setSpacing(verticalSpacing); __ 也可以应用于网格布局
    boxLayout->setSpacing(horizontalSpacing); __ 适用于弹性布局
    设置QMargins
    QMargins类用于设置控件周围的外边距,
    cpp
    QMargins margins(10, 20, 10, 20); __ 左上右下,分别代表左间距、上间距、右间距、下间距
    horizontalLayout->setMargins(margins);
    示例,完整的布局与间距控制
    以下是一个完整的示例,展示了如何创建一个包含按钮的水平布局,并设置相应的间距,
    cpp
    include <QApplication>
    include <QWidget>
    include <QHBoxLayout>
    include <QPushButton>
    include <QSpacing>
    include <QMargins>
    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    QWidget window;
    QHBoxLayout *layout = new QHBoxLayout(&window);
    __ 创建按钮
    QPushButton *button1 = new QPushButton(按钮1);
    QPushButton *button2 = new QPushButton(按钮2);
    QPushButton *button3 = new QPushButton(按钮3);
    __ 设置间距
    QSpacing horizontalSpacing(20);
    layout->setSpacing(horizontalSpacing);
    __ 设置外边距
    QMargins margins(10, 20, 10, 20);
    layout->setMargins(margins);
    __ 添加按钮到布局
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    window.show();
    return app.exec();
    }
    在上面的代码中,我们创建了一个窗口和一个水平布局,向布局中添加了三个按钮,并设置了它们之间的水平间距为20像素,同时为整个布局设置了外边距。
    通过这些方法,您可以轻松地控制QT Widgets界面中的元素对齐与间距,从而创建出既美观又实用的用户界面。

1.4 1_4_响应式设计实战

1.4.1 1_4_响应式设计实战

1_4_响应式设计实战
1_4_响应式设计实战
在当今的软件开发中,响应式设计已成为一项至关重要的技能,它能确保应用程序在不同尺寸和分辨率的设备上均能提供良好的用户体验。Qt作为一套成熟的跨平台C++图形用户界面应用程序框架,提供了强大的工具和功能来实现响应式设计。

  1. 使用Qt的布局系统
    Qt的布局系统是实现响应式设计的基础。通过使用QHBoxLayout、QVBoxLayout、QGridLayout等布局管理器,我们可以轻松地创建自适应不同屏幕尺寸的界面。布局管理器能够自动调整控件的大小和位置,以适应容器的大小变化。
  2. 媒体查询
    Qt也支持通过媒体查询来定义不同设备和屏幕尺寸的样式表。我们可以使用@media规则来指定特定屏幕尺寸范围内的样式变化,从而实现针对不同设备的响应式设计。
  3. 灵活的控件使用
    在Qt中,很多控件都是可伸缩的,比如QTableView、QListView和QComboBox等。合理使用这些控件,可以让它们在不同尺寸的屏幕上自动调整布局和显示内容。
  4. 事件处理
    对于一些需要根据用户操作来调整界面响应的场合,我们可以通过捕捉鼠标事件、键盘事件等来动态调整控件的大小和位置,从而实现更加灵活的响应式设计。
  5. 使用Qt Quick
    对于需要更高性能和更复杂交互的界面设计,Qt Quick成为了一个强大的选择。Qt Quick Controls 2是Qt 6中引入的模块,它提供了一组现代化的UI组件,这些组件是响应式的,可以轻松适应不同的屏幕尺寸和方向。
    实战案例
    让我们通过一个简单的实战案例来演示如何使用Qt来创建一个响应式的界面。
    首先,我们创建一个垂直布局,并在其中添加两个按钮和一个标签。我们会在按钮的点击事件中动态改变标签的内容,以演示界面的响应性。
    cpp
    __ 创建一个QWidget作为主窗口
    QWidget window;
    window.setWindowTitle(响应式设计实战);
    __ 创建一个垂直布局
    QVBoxLayout layout(&window);
    __ 创建一个标签
    QLabel label(欢迎使用Qt!);
    __ 创建两个按钮
    QPushButton button1(点击改变标签);
    QPushButton button2(再次点击改变标签);
    __ 将控件添加到布局中
    layout.addWidget(&label);
    layout.addWidget(&button1);
    layout.addWidget(&button2);
    __ 连接按钮的点击事件
    QObject::connect(&button1, &QPushButton::clicked, & {
    label.setText(按钮1被点击!);
    });
    QObject::connect(&button2, &QPushButton::clicked, & {
    label.setText(按钮2被点击!);
    });
    __ 显示窗口
    window.show();
    在上面的代码中,我们创建了一个简单的界面,其中包含一个标签和两个按钮。点击按钮1或按钮2时,标签的内容会发生变化。这个简单的例子展示了如何通过Qt的布局系统和事件处理机制来实现一个基本的响应式设计。
    在实际的应用程序中,你可能需要考虑更加复杂的布局和交互,但是基本的思想是类似的,使用布局来管理控件的位置和大小,使用事件来处理用户的操作,使用媒体查询来针对不同的设备提供不同的样式。通过这些方法,我们可以有效地实现响应式设计,提升用户体验。

1.5 1_5_界面设计中的色彩与字体优化

1.5.1 1_5_界面设计中的色彩与字体优化

1_5_界面设计中的色彩与字体优化
1.5 界面设计中的色彩与字体优化
在QT Widgets界面编程中,色彩与字体是至关重要的元素,它们不仅能影响到界面的美观程度,还能对用户的体验产生直接的影响。本节将详细介绍如何在QT界面设计中进行色彩与字体的优化。
一、色彩优化
色彩是界面设计中最重要的元素之一,合理的色彩搭配能够使界面更加美观,更能吸引用户的注意力。以下是一些色彩优化的建议,

  1. 使用统一的色彩风格,整个应用的界面应该使用统一的色彩风格,包括主题色、辅助色等。这样可以增加应用的专业性和一致性。
  2. 保持色彩的简洁性,避免在界面上使用过多的色彩,过多的色彩会使界面显得杂乱无章。一般来说,一个界面中的主色不应超过3种。
  3. 注意色彩的对比度,色彩的对比度对于界面的可读性非常重要。在设计界面时,应确保文字和背景的色彩对比度足够大,以便用户能够清晰地阅读。
  4. 利用色彩的心理效应,不同的色彩会给人不同的心理感受,例如,蓝色给人以安静、清爽的感觉,红色给人以热情、活泼的感觉。在设计界面时,可以利用这些色彩心理效应来传达特定的情感。
    二、字体优化
    字体是界面设计中另一个重要的元素,合适的字体可以提高界面的美感,同时也能让用户更容易阅读。以下是一些字体优化的建议,
  5. 使用易读的字体,在设计界面时,应选择易读性好的字体,以便用户能够轻松地阅读。例如,微软雅黑、宋体、黑体等都是不错的选择。
  6. 保持字体的简洁性,避免在界面上使用过多的字体,过多的字体会使界面显得杂乱无章。一般来说,一个界面中的主字体不应超过2种。
  7. 注意字体的字号和行距,字体的字号和行距对于界面的可读性非常重要。在设计界面时,应确保文字的字号足够大,行距合适,以便用户能够清晰地阅读。
  8. 利用字体的情感效应,不同的字体会给人不同的情感感受,例如,粗体给人以力量、坚定的感觉,细体给人以柔美、细腻的感觉。在设计界面时,可以利用这些字体的情感效应来传达特定的情感。
    通过以上的色彩与字体优化,可以使得QT Widgets界面更加美观、易读,提升用户的体验。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

2 QT_Widgets界面元素定制

2.1 2_1_控件样式定制基础

2.1.1 2_1_控件样式定制基础

2_1_控件样式定制基础
2.1 控件样式定制基础
控件样式是图形用户界面设计中的一个重要方面,它能够增强应用程序的视觉效果和用户体验。Qt提供了强大的样式定制功能,使得开发者可以轻松地改变控件的外观。在Qt中,样式定制主要通过QSS(Qt Style Sheets)来实现。
2.1.1 QSS简介
QSS(Qt Style Sheets)是一种CSS(Cascading Style Sheets,层叠样式表)的Qt专用版本,用于定制Qt应用程序的控件样式。它具有CSS的所有特点,如简洁的语法、易于理解和维护等。通过QSS,开发者可以非常方便地修改应用程序的外观,而无需修改源代码。
QSS的基本语法与CSS类似,主要包括选择器和属性值。选择器用于指定需要定制的控件,属性值用于设置控件的样式。例如,
QPushButton {
background-color: yellow;
border: 1px solid red;
}
这个样式规则将所有QPushButton控件的背景颜色设置为黄色,边框设置为1像素宽的红色实线。
2.1.2 样式定制方法
在Qt应用程序中,可以通过以下几种方法来应用样式,

  1. 内联样式,直接在控件的属性中设置样式。例如,
    QPushButton *btn = new QPushButton(按钮);
    btn->setStyleSheet(background-color: yellow; border: 1px solid red;);
    这个方法适用于单个控件的样式定制。
  2. 外部样式表,将样式规则写在一个独立的QSS文件中,通过QApplication::setStyleSheet()方法应用到整个应用程序。例如,
    __ 样式表文件 styles.qss
    QPushButton {
    background-color: yellow;
    border: 1px solid red;
    }
    __ 主窗口文件 mainwindow.cpp
    include mainwindow.h
    include ._styles.qss
    MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    {
    QFile file(styles.qss);
    if (file.open(QIODevice::ReadOnly)) {
    QString styleSheet = QLatin1String(file.readAll());
    qApp->setStyleSheet(styleSheet);
    }
    QPushButton *btn = new QPushButton(按钮);
    setCentralWidget(btn);
    }
    这个方法适用于整个应用程序的样式定制。
  3. 主题样式表,将样式规则集成到Qt主题文件中,通过QApplication::setStyle()方法应用到整个应用程序。这种方式通常用于定制整个Qt框架的样式,而不仅仅是单个应用程序。
    2.1.3 常用样式属性
    在QSS中,可以设置控件的各种样式属性,如颜色、字体、边框、背景等。以下是一些常用的样式属性,
  • color,设置文本颜色。
  • background-color,设置背景颜色。
  • font,设置字体,如font: 12px 微软雅黑;。
  • border,设置边框,如border: 1px solid red;。
  • margin,设置外边距,如margin: 5px;。
  • padding,设置内边距,如padding: 5px;。
  • width、height,设置宽度和高度。
  • min-width、min-height,设置最小宽度和高度。
  • max-width、max-height,设置最大宽度和高度。
    通过合理地使用这些属性,开发者可以灵活地定制控件的样式,创造出符合自己需求的界面效果。

2.2 2_2_高级控件样式技巧

2.2.1 2_2_高级控件样式技巧

2_2_高级控件样式技巧
2_2_高级控件样式技巧
在QT Widgets应用程序中,样式是美化界面的重要手段。通过样式,我们可以改变控件的颜色、字体、边距等属性,使得界面更加美观和易于使用。本节将介绍一些高级控件样式技巧,帮助读者打造出色的用户界面。

  1. 使用样式表
    样式表是QT中设置控件样式的主要方式。通过样式表,我们可以为控件指定颜色、字体、边距等属性。以下是一个简单的样式表示例,
    css
    QPushButton {
    background-color: ffcc00;
    border-style: outset;
    border-width: 2px;
    border-radius: 10px;
    border-color: beige;
    font: bold 14px;
    min-width: 10em;
    padding: 6px;
    }
    QPushButton:hover {
    background-color: ff9900;
    }
    QPushButton:pressed {
    background-color: ff6600;
    border-style: inset;
    }
    上述样式表定义了一个按钮的样式,包括背景颜色、边框样式、字体等。同时,还定义了按钮悬停和按下时的样式。通过应用这个样式表,我们可以快速为按钮设置所需的样式。
  2. 继承样式
    QT支持样式继承,这意味着我们可以为控件的子控件继承父控件的样式。例如,以下样式表将应用于所有QPushButton的子控件,
    css
    QPushButton QAbstractButton {
    background-color: ffcc00;
    border-style: outset;
    border-width: 2px;
    border-radius: 10px;
    border-color: beige;
    font: bold 14px;
    min-width: 10em;
    padding: 6px;
    }
    QPushButton:hover QAbstractButton {
    background-color: ff9900;
    }
    QPushButton:pressed QAbstractButton {
    background-color: ff6600;
    border-style: inset;
    }
    通过这种方式,我们可以为特定类型的控件(如QPushButton)的子控件应用样式,而不需要为每个子控件单独设置样式。
  3. 使用动态样式
    动态样式允许我们在运行时改变控件的样式。这可以通过QSS(QT Style Sheets)来实现。以下是一个简单的动态样式示例,
    cpp
    QPushButton *button = new QPushButton(按钮, this);
    __ 连接信号和槽,当按钮被点击时改变其样式
    connect(button, &QPushButton::clicked, button {
    if (button->isChecked()) {
    button->setStyleSheet(QPushButton { background-color: red; });
    } else {
    button->setStyleSheet(QPushButton { background-color: green; });
    }
    });
    在这个示例中,我们创建了一个按钮,并连接了其点击信号到一个Lambda函数。当按钮被点击时,Lambda函数将改变按钮的背景颜色。这种方式使得我们可以在程序运行时动态地改变控件的样式,以实现各种交互效果。
  4. 使用自定义绘图
    除了使用预定义的控件样式,我们还可以通过自定义绘图来实现高级样式效果。例如,以下代码将创建一个自定义的QPushButton,其背景为一个渐变图像,
    cpp
    class GradientButton : public QPushButton {
    public:
    GradientButton(QWidget *parent = nullptr) : QPushButton(parent) {
    __ 设置渐变图像
    QLinearGradient gradient(0, 0, width(), height());
    gradient.setColorAt(0, QColor(255, 0, 0));
    gradient.setColorAt(1, QColor(0, 255, 0));
    setStyleSheet(QPushButton { background-image: linear-gradient(to right,
    QLineF(0, 0, width(), height()),
    QLineF(0, 0, width(), height())); });
    }
    void paintEvent(QPaintEvent *event) override {
    __ 绘制渐变图像
    QPainter painter(this);
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.drawImage(rect(), QImage(gradient.png));
    painter.end();
    __ 调用基类绘制方法
    QPushButton::paintEvent(event);
    }
    };
    在这个示例中,我们创建了一个自定义的QPushButton类,其背景为一个渐变图像。通过使用QLinearGradient类和QPainter类,我们可以轻松地创建各种复杂的绘图效果,以实现高级控件样式。
    通过以上技巧,我们可以为QT Widgets应用程序创建出色的用户界面。在实际开发过程中,可以根据具体需求灵活运用这些技巧,打造美观、易用的应用程序。

2.3 2_3_动态控件样式应用

2.3.1 2_3_动态控件样式应用

2_3_动态控件样式应用
2.3 动态控件样式应用
在QTWidgets应用程序中,样式表(Style Sheets)是一个强大的工具,它允许开发人员通过CSS风格的规则来定制应用程序的外观和风格。在QT中,样式表不仅可以应用于整个窗口或控件,还可以应用于控件的各个状态,如正常状态、鼠标悬停状态、禁用状态等。
本节将介绍如何在QT Widgets应用程序中动态地应用样式表,以实现界面元素的个性化设计。
2.3.1 基本样式表
首先,让我们从一个简单的样式表开始,它将改变一个按钮的颜色和字体。
假设我们有一个按钮,我们想要将其文本颜色更改为红色,背景颜色更改为蓝色,并且字体加粗。
qss
QPushButton {
background-color: blue;
color: red;
font: bold 14px;
}
以上样式表规则应用于QPushButton控件,其中,

  • background-color 设置了按钮的背景颜色。
  • color 设置了按钮文本的颜色。
  • font 设置了按钮文本的字体和大小。
    在QT中,可以通过两种主要方式应用样式表,内联样式和外部样式表文件。
    2.3.1.1 内联样式
    内联样式直接在控件的属性中设置,例如,
    cpp
    QPushButton myButton = new QPushButton(点击我, this);
    myButton->setStyleSheet(background-color: blue; color: red; font: bold 14px;);
    这种方式非常方便,可以快速修改单个控件的样式。但是,如果样式需要重复使用,这种方式可能会导致代码冗余。
    2.3.1.2 外部样式表文件
    更好的做法是将样式表保存在单独的CSS文件中,这样可以在多个窗口和控件中重用样式。例如,创建一个名为style.qss的文件,
    qss
    _
    style.qss *_
    QPushButton {
    background-color: blue;
    color: red;
    font: bold 14px;
    }
    然后在主窗口的构造函数中加载这个样式表,
    cpp
    QMainWindow::QMainWindow(QWidget *parent)
    : QMainWindow(parent)
    {
    __ 设置样式表文件
    QFile styleFile(style.qss);
    styleFile.open(QFile::ReadOnly);
    QString styleSheet = QLatin1String(styleFile.readAll());
    this->setStyleSheet(styleSheet);
    }
    这种方式非常适合应用程序的样式统一,只需在一个地方修改样式,所有相应的控件都会更新。
    2.3.2 动态样式表
    除了静态样式,QT还允许我们动态地更改控件的样式。例如,我们可以根据用户的操作或其他应用程序状态来改变按钮的颜色。
    假设我们希望当按钮被鼠标悬停时,其背景颜色变为绿色。
    cpp
    QPushButton *myButton = new QPushButton(点击我, this);
    __ 鼠标悬停时的样式
    QString hoverStyle = background-color: green;;
    __ 连接信号和槽
    QObject::connect(myButton, &QPushButton::entered, = {
    myButton->setStyleSheet(hoverStyle);
    });
    QObject::connect(myButton, &QPushButton::leaved, = {
    myButton->setStyleSheet(); __ 清除样式
    });
    在这个例子中,我们使用了信号和槽机制来响应鼠标进入和离开按钮的事件。当鼠标悬停进入按钮时,我们设置了一个新的样式表;当鼠标离开时,我们恢复了按钮的默认样式。
    2.3.3 状态样式
    QT还允许我们为控件的不同状态定义样式。例如,我们可以为按钮定义按下状态的样式,
    cpp
    QPushButton *myButton = new QPushButton(点击我, this);
    __ 按下状态的样式
    QString pressedStyle = background-color: red; color: white;;
    __ 连接信号和槽
    QObject::connect(myButton, &QPushButton::pressed, = {
    myButton->setStyleSheet(pressedStyle);
    });
    QObject::connect(myButton, &QPushButton::released, = {
    myButton->setStyleSheet(); __ 清除样式
    });
    在这个例子中,当按钮被按下时,我们将应用一个新的样式表,更改背景颜色和文本颜色。当按钮被释放时,我们恢复默认样式。
    通过这种方式,我们可以轻松地创建动态和交互式的用户界面,提高用户体验。
    2.3.4 高级样式表
    样式表支持CSS的所有基本功能,包括伪类、伪元素、选择器、继承和层叠等。这使得我们可以创建非常复杂的样式。
    例如,我们可以定义一个QSpinBox控件,当它处于焦点状态时,其背景色和边框颜色发生变化,
    cpp
    QSpinBox *mySpinBox = new QSpinBox(this);
    __ 焦点状态的样式
    QString focusedStyle = background-color: yellow; border: 2px solid black;;
    __ 连接信号和槽
    QObject::connect(mySpinBox, &QSpinBox::focusInEvent, [=](QFocusEvent *e) {
    mySpinBox->setStyleSheet(focusedStyle);
    });
    QObject::connect(mySpinBox, &QSpinBox::focusOutEvent, [=](QFocusEvent *e) {
    mySpinBox->setStyleSheet(); __ 清除样式
    });
    在这个例子中,当QSpinBox获得焦点时,我们将应用一个新的样式表,更改背景颜色和边框。当它失去焦点时,我们将恢复默认样式。
    通过使用高级样式表,我们可以实现非常个性化的界面设计,提高应用程序的专业性和吸引力。
    总结
    样式表是QTWidgets应用程序中定制界面的重要工具。通过使用内联样式、外部样式表文件、动态样式和状态样式,我们可以创建动态、交互式的用户界面,提高用户体验。高级样式表功能使我们能够实现非常复杂和个性化的界面设计。

2.4 2_4_控件状态变化处理

2.4.1 2_4_控件状态变化处理

2_4_控件状态变化处理
2_4_控件状态变化处理
在QTWidgets应用程序中,控件状态变化处理是指对控件的各种状态进行监控和响应,以便在状态发生变化时执行相应的操作。控件状态变化处理是界面编程中非常关键的一部分,它可以使应用程序具有更好的交互性和用户体验。
在QT中,控件状态变化处理主要通过信号和槽机制来实现。当控件的状态发生变化时,它会发出一个信号,然后通过连接的槽来执行相应的操作。例如,当一个按钮被点击时,它会发出一个clicked信号,我们可以连接这个信号到一个槽函数来执行按钮点击后的操作。
在本节中,我们将介绍如何使用QT的信号和槽机制来处理控件状态变化,以及如何使用QT提供的各种控件状态变化处理方法。我们将通过一个简单的示例来演示控件状态变化处理的基本原理和应用。
示例,一个简单的按钮状态变化处理
假设我们想要创建一个简单的QTWidgets应用程序,当用户点击一个按钮时,程序会在控制台上打印一条消息。我们可以使用QPushButton控件来实现这个功能。
首先,我们需要在主窗口类中定义一个按钮控件和一个槽函数,用于处理按钮点击事件。以下是一个简单的示例代码,
cpp
include <QApplication>
include <QPushButton>
include <QWidget>
include <iostream>
class MainWindow : public QWidget {
Q_OBJECT
public:
MainWindow() {
QPushButton *btn = new QPushButton(点击我, this);
connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
}
private slots:
void onButtonClicked() {
std::cout << 按钮被点击了 << std::endl;
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
return app.exec();
}
在上面的示例中,我们首先包含了必要的头文件,然后创建了一个名为MainWindow的主窗口类。在构造函数中,我们创建了一个QPushButton控件,并将其添加到主窗口中。然后,我们使用connect函数将按钮的clicked信号连接到onButtonClicked槽函数上。
onButtonClicked槽函数是一个私有槽函数,它会在按钮被点击时被调用。在这个示例中,我们简单地在槽函数中打印了一条消息。当然,你可以在槽函数中执行任何你需要的操作,例如更新界面、发送网络请求等。
在上面的示例中,我们使用了QPushButton的clicked信号来处理按钮点击事件。除了clicked信号之外,QT还提供了许多其他控件状态变化信号,例如,

  • pressed信号,当控件被按下时发出。
  • released信号,当控件被释放时发出。
  • toggled信号,当控件的状态被切换时发出,例如复选框或单选按钮。
    你可以根据需要使用这些信号来处理控件的状态变化。同时,你也可以通过继承QT的控件类并重写相关的方法来监听和处理控件的状态变化。
    总结
    在本节中,我们介绍了QTWidgets应用程序中控件状态变化处理的基本原理和应用。我们通过一个简单的示例演示了如何使用QT的信号和槽机制来处理按钮点击事件。同时,我们还提到了QT提供的其他控件状态变化信号,以及如何根据需要使用它们来处理控件的状态变化。

2.5 2_5_界面元素动画效果实现

2.5.1 2_5_界面元素动画效果实现

2_5_界面元素动画效果实现
2.5 界面元素动画效果实现
在QTWidgets编程中,动画可以为界面增添生动活泼的元素,提升用户体验。QT提供了多种方法来创建和控制动画。本节将介绍如何使用QT中的动画功能为界面元素添加动画效果。
使用QPropertyAnimation实现动画
QPropertyAnimation是QT中用于动画化对象属性的类。通过这个类,我们可以对对象的属性值进行平滑的过渡动画效果,如大小、位置、透明度等。
示例,
假设我们有一个QPushButton,我们希望在其点击时,将按钮的大小放大然后再恢复原状。
cpp
QPropertyAnimation *animation = new QPropertyAnimation(pushButton, size);
animation->setDuration(500); __ 设置动画持续时间为500毫秒
animation->setStartValue(QSize(80, 30)); __ 设置动画开始时的大小
animation->setEndValue(QSize(100, 50)); __ 设置动画结束时的大小
QObject::connect(pushButton, &QPushButton::clicked, ={
animation->start();
});
在上面的代码中,我们创建了一个QPropertyAnimation对象,并连接到了按钮的clicked信号。当按钮被点击时,动画开始,按钮的大小将从80x30像素平滑过渡到100x50像素,然后恢复原状。
使用QAbstractAnimation实现复杂动画
除了QPropertyAnimation,QT还提供了QAbstractAnimation类,它是所有动画类的基类。通过继承这个类,可以创建自定义的动画效果。
示例,
我们想要实现一个自定义的动画效果,比如一个按钮在点击时进行旋转。
cpp
class RotationAnimation : public QAbstractAnimation {
Q_OBJECT
public:
RotationAnimation(QObject *parent = nullptr) : QAbstractAnimation(parent) {
setDuration(500); __ 设置动画持续时间为500毫秒
}
protected:
void updateCurrentTime(qreal t) override {
if (object()) {
QTransform transform;
transform.rotate(static_cast<int>(t * 360));
object()->setTransform(transform);
}
}
};
__ 使用示例
RotationAnimation *rotation = new RotationAnimation(pushButton);
rotation->setLoopCount(1); __ 设置动画循环次数为1次
pushButton->setProperty(rotationAnimation, QVariant::fromValue(rotation));
QObject::connect(pushButton, &QPushButton::clicked, ={
rotation->start();
});
在上面的代码中,我们创建了一个RotationAnimation类,它在动画的每个时间点更新按钮的旋转角度。然后,我们将这个动画连接到按钮的clicked信号,当按钮被点击时,动画开始,按钮将进行旋转。
使用QSequentialAnimationGroup组合动画
在某些情况下,我们可能希望同时对多个界面元素进行动画效果,或者对一个元素执行多个动画。这时可以使用QSequentialAnimationGroup来将多个动画顺序组合起来。
示例,
我们有两个按钮,我们希望当第一个按钮被点击时,先放大,然后第二个按钮缩小。
cpp
QSequentialAnimationGroup *group = new QSequentialAnimationGroup();
QPropertyAnimation *pushButtonAnimation1 = new QPropertyAnimation(pushButton1, size);
pushButtonAnimation1->setDuration(500);
pushButtonAnimation1->setStartValue(QSize(80, 30));
pushButtonAnimation1->setEndValue(QSize(120, 40));
QPropertyAnimation *pushButtonAnimation2 = new QPropertyAnimation(pushButton2, size);
pushButtonAnimation2->setDuration(500);
pushButtonAnimation2->setStartValue(QSize(80, 30));
pushButtonAnimation2->setEndValue(QSize(60, 20));
group->addAnimation(pushButtonAnimation1);
group->addAnimation(pushButtonAnimation2);
QObject::connect(pushButton1, &QPushButton::clicked, ={
group->start();
});
在上面的代码中,我们创建了一个QSequentialAnimationGroup对象,并将两个QPropertyAnimation对象添加到这个组中。当第一个按钮被点击时,组中的动画将按顺序执行,首先放大第一个按钮,然后缩小第二个按钮。
通过上述的方法,我们可以实现各种复杂的界面元素动画效果,提升用户界面的动态感和交互性。在实际开发中,应根据实际需求选择合适的动画类

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

3 QT_Widgets事件处理

3.1 3_1_事件处理机制解析

3.1.1 3_1_事件处理机制解析

3_1_事件处理机制解析
3.1 事件处理机制解析
在Qt中,事件是用户与应用程序交互的基础。Qt框架提供了一套完善的事件处理机制,使得开发者可以轻松地处理各种事件。本节将详细解析Qt的事件处理机制。
3.1.1 事件的概念
在Qt中,事件是应用程序执行过程中的一个瞬间,它可以是用户的输入(如鼠标点击、键盘按键),也可以是系统消息(如定时器消息、窗口状态改变)。Qt将所有这些瞬间抽象为事件,并提供相应的事件处理函数来响应用户和系统发出的信号。
3.1.2 事件处理机制
Qt的事件处理机制主要由以下几个部分组成,

  1. 事件生成,当用户或系统产生一个动作时,Qt会生成一个相应的事件。例如,点击鼠标会生成一个QMouseEvent事件,定时器到达预设时间会生成一个QTimerEvent事件。
  2. 事件传递,事件生成后,Qt会按照事件传递机制将事件传递给相应的对象。Qt的事件传递机制是层层传递的,从最顶层的窗口开始,依次传递给其子窗口,直到找到一个能够处理该事件的对象。
  3. 事件过滤,在事件传递过程中,如果某个对象不想处理某个事件,可以将事件传递给它的父对象或其他对象进行处理。这种机制称为事件过滤。
  4. 事件处理,最终,事件会传递到能够处理它的对象。这个对象会调用相应的事件处理函数来响应该事件。事件处理函数通常是重写的虚函数,如mousePressEvent()、timerEvent()等。
  5. 事件队列,Qt将所有事件存储在一个事件队列中,按照顺序等待处理。这样,即使有多个事件同时发生,Qt也能保证它们按照生成顺序被处理。
    3.1.3 事件处理函数
    Qt为各种事件提供了相应的事件处理函数。这些函数大多数是虚函数,可以在派生类中重写以实现特定的事件处理逻辑。下面列出了一些常用的事件处理函数,
  • mousePressEvent(QMouseEvent *event),处理鼠标按下事件。
  • mouseReleaseEvent(QMouseEvent *event),处理鼠标释放事件。
  • mouseDoubleClickEvent(QMouseEvent *event),处理鼠标双击事件。
  • keyPressEvent(QKeyEvent *event),处理键盘按下事件。
  • keyReleaseEvent(QKeyEvent *event),处理键盘释放事件。
  • timerEvent(QTimerEvent *event),处理定时器事件。
  • paintEvent(QPaintEvent *event),处理绘制事件。
    3.1.4 事件处理实践
    下面通过一个简单的例子来演示如何处理一个鼠标点击事件。
    cpp
    class MyWidget : public QWidget {
    Q_OBJECT
    public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
    __ 构造函数
    }
    protected:
    void mousePressEvent(QMouseEvent *event) override {
    __ 重写mousePressEvent函数来处理鼠标点击事件
    if (event->button() == Qt::LeftButton) {
    qDebug() << Left button clicked;
    } else if (event->button() == Qt::RightButton) {
    qDebug() << Right button clicked;
    }
    __ 调用基类的mousePressEvent函数
    QWidget::mousePressEvent(event);
    }
    };
    在上面的代码中,我们重写了MyWidget类的mousePressEvent函数。当鼠标点击事件发生时,该函数会被调用。在这个例子中,我们检查了点击的是哪个鼠标按钮,并在控制台中打印出相应的信息。
    3.1.5 小结
    Qt的事件处理机制是一种事件驱动的编程模型,它使得处理各种事件变得简单而直观。通过重写事件处理函数,开发者可以轻松地为应用程序添加丰富的交互功能。在下一节中,我们将学习如何使用信号和槽来实现对象之间的通信。

3.2 3_2_鼠标事件实战技巧

3.2.1 3_2_鼠标事件实战技巧

3_2_鼠标事件实战技巧
3_2_鼠标事件实战技巧
在QTWidgets应用程序中,鼠标事件是用户与界面交互的基础之一。QT提供了丰富的鼠标事件处理机制,使得开发者可以轻松地捕捉和处理鼠标事件。本节将介绍一些关于鼠标事件的实战技巧。

  1. 鼠标事件概述
    在QT中,鼠标事件分为以下几种类型,
  • 鼠标按下事件(QMouseEvent::MouseButtonPress)
  • 鼠标释放事件(QMouseEvent::MouseButtonRelease)
  • 鼠标移动事件(QMouseEvent::MouseButtonDblClick)
  • 鼠标双击事件(QMouseEvent::MouseButtonDblClick)
  • 鼠标拖动事件(QMouseEvent::MouseButtonDblClick)
    这些事件可以通过继承QWidget类并重写其mousePressEvent、mouseReleaseEvent、mouseMoveEvent、mouseDoubleClickEvent等方法来处理。
  1. 鼠标事件实战技巧
    下面我们将通过一个简单的示例来演示如何使用QT处理鼠标事件。本示例将实现一个自定义的QWidget类,用于绘制一个矩形区域。
    首先,创建一个名为MyWidget的类,继承自QWidget。在MyWidget类中,我们需要重写以下几个方法,
    (1)mousePressEvent(鼠标按下事件)
    当用户按下鼠标时,该方法将被调用。在这个方法中,我们可以记录鼠标的初始位置,以便在后续的mouseMoveEvent方法中使用。
    cpp
    void MyWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
    __ 记录鼠标的初始位置
    startPos = event->pos();
    }
    }
    (2)mouseMoveEvent(鼠标移动事件)
    当用户移动鼠标时,如果鼠标按钮被按下,这个方法将被调用。在这个方法中,我们可以根据鼠标的当前位置和起始位置来绘制矩形。
    cpp
    void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (event->buttons() == Qt::LeftButton && startPos.isValid()) {
    __ 更新矩形的起始位置和结束位置
    rect = QRect(startPos, event->pos());
    update(); __ 请求重绘
    }
    }
    (3)mouseReleaseEvent(鼠标释放事件)
    当用户释放鼠标按钮时,这个方法将被调用。在这个方法中,我们可以清除起始位置,以便开始一个新的矩形绘制。
    cpp
    void MyWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
    startPos = QPoint(); __ 清除起始位置
    }
    }
  2. 运行示例
    现在,我们来运行这个示例。首先,创建一个MyWidget类的实例,并将其设置为窗口的中央控件。然后,连接MyWidget的mousePressEvent、mouseMoveEvent和mouseReleaseEvent信号与相应的槽函数。
    cpp
    MyWidget *myWidget = new MyWidget;
    myWidget->mousePressEvent(nullptr);
    myWidget->mouseMoveEvent(nullptr);
    myWidget->mouseReleaseEvent(nullptr);
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(myWidget);
    运行程序后,当我们在MyWidget控件上按下鼠标时,将会开始绘制矩形。当移动鼠标时,矩形将随着鼠标的移动而更新。当释放鼠标按钮时,矩形将保持绘制在界面上,同时清除起始位置,以便开始一个新的矩形绘制。
    通过这个简单的示例,我们可以看到QT中处理鼠标事件是多么的简单和强大。开发者可以根据实际需求,灵活地使用鼠标事件来实现各种交互功能。

3.3 3_3_键盘事件处理技巧

3.3.1 3_3_键盘事件处理技巧

3_3_键盘事件处理技巧
3.3 键盘事件处理技巧
在QT Widgets应用程序中,处理键盘事件是用户交互的一个重要部分。QT提供了丰富的信号和槽机制来处理各种键盘事件。本节将介绍如何使用QT Widgets来捕捉和处理键盘事件,并提供一些实用的技巧。
3.3.1 捕捉键盘事件
在QT中,捕捉键盘事件主要依赖于继承自QWidget的类的installEventFilter方法。要处理键盘事件,首先需要重写目标控件的keyPressEvent、keyReleaseEvent或者keyEvent方法。
示例,
cpp
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
__ 安装事件过滤器
installEventFilter(this);
}
protected:
__ 重写keyPressEvent来处理键盘按下事件
void keyPressEvent(QKeyEvent *event) override {
__ 处理按键事件,例如,打印按下的键
qDebug() << Key Pressed: << event->text();
}
__ 重写keyReleaseEvent来处理键盘释放事件
void keyReleaseEvent(QKeyEvent *event) override {
__ 处理释放键事件
qDebug() << Key Released: << event->text();
}
__ 使用installEventFilter来安装事件过滤器
bool eventFilter(QObject *obj, QEvent *event) override {
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
__ 处理其他控件传递过来的键盘事件
qDebug() << Key Event Caught!;
return true; __ 处理了事件,不继续传递
}
return QWidget::eventFilter(obj, event);
}
};
在上面的代码中,我们通过重写keyPressEvent和keyReleaseEvent来处理键盘事件。同时,为了能够捕捉到子控件上的键盘事件,我们使用了installEventFilter方法来安装事件过滤器。在eventFilter方法中,我们检查了事件类型,并对键盘事件进行了处理。
3.3.2 常用键盘事件处理技巧

  1. 快捷键设置,
    你可以为应用程序或者特定窗口设置快捷键。使用QShortcut类可以轻松实现。
    cpp
    QShortcut *quitShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
    connect(quitShortcut, &QShortcut::activated, this, &MyWidget::close);

    上述代码为关闭窗口设置了快捷键Ctrl+Q。

  2. 文本输入控制,
    如果你需要控制文本框内的键盘输入,可以使用QLineEdit、QTextEdit等控件的textChanged信号来监控文本变化。
    cpp
    QLineEdit *lineEdit = new QLineEdit(this);
    QObject::connect(lineEdit, &QLineEdit::textChanged, [=](const QString &text) {
    qDebug() << Current Text: << text;
    });

  3. 特殊按键处理,
    某些特殊按键(如F1-F12、功能键等)在默认情况下会被操作系统或其他应用程序占用。可以通过设置Qt::WidgetShortcut标志来绕过这一限制。
    cpp
    QShortcut *funcShortcut = new QShortcut(QKeySequence(Qt::F1), this);
    connect(funcShortcut, &QShortcut::activated, this, &MyWidget::handleFunctionKey);

    在handleFunctionKey槽函数中,你可以处理这些特殊按键。

  4. 组合按键检测,
    有时你可能需要检测组合键,如Ctrl+Alt+Delete。这可以通过设置Qt::KeyboardModifier标志和相应按键来实现。
    cpp
    QShortcut *combinationShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Delete), this);
    connect(combinationShortcut, &QShortcut::activated, this, &MyWidget::handleCombinationKey);

    在handleCombinationKey槽函数中,你可以处理这种复杂的组合按键。
    通过上述技巧,你可以更加灵活地处理QT Widgets应用程序中的键盘事件,为用户提供丰富

3.4 3_4_触摸事件编程实战

3.4.1 3_4_触摸事件编程实战

3_4_触摸事件编程实战
3.4 触摸事件编程实战
在Qt中,触摸事件是用户通过触摸屏与应用程序交互时产生的一类事件。在编写本书时,触摸屏设备已经非常普及,因此,熟练掌握触摸事件编程对于开发出友好、响应迅速的用户界面至关重要。
3.4.1 触摸事件类型
在Qt中,触摸事件主要包括以下几种类型,

  • QTouchEvent,这是基本的触摸事件类型,包含了触摸点的位置信息。
  • QTouchEvent::TouchBegin,当一个触摸点被按下时产生。
  • QTouchEvent::TouchUpdate,当触摸点在屏幕上移动时产生。
  • QTouchEvent::TouchEnd,当触摸点被释放时产生。
  • QTouchEvent::TouchCancel,当触摸事件被系统取消时产生,比如有更高优先级的任务需要处理。
    3.4.2 处理触摸事件
    要在Qt应用程序中处理触摸事件,首先需要在类中继承QObject并重新实现事件处理函数touchEvent。下面是一个简单的例子,展示了如何在继承自QWidget的类中处理触摸事件,
    cpp
    class TouchWidget : public QWidget {
    Q_OBJECT
    public:
    TouchWidget(QWidget *parent = nullptr) : QWidget(parent) {
    __ 设置触摸屏的缩放和旋转支持
    setTouchPointScaleEnabled(true);
    setTouchMatrixEnabled(true);
    }
    protected:
    void touchEvent(QTouchEvent *event) override {
    switch (event->type()) {
    case QTouchEvent::TouchBegin:
    __ 处理触摸点开始触摸的事件
    break;
    case QTouchEvent::TouchUpdate:
    __ 处理触摸点移动的事件
    break;
    case QTouchEvent::TouchEnd:
    __ 处理触摸点结束触摸的事件
    break;
    case QTouchEvent::TouchCancel:
    __ 处理触摸事件被取消的事件
    break;
    default:
    __ 默认处理其他触摸事件
    break;
    }
    __ 事件传递给父类处理
    QWidget::touchEvent(event);
    }
    };
    在上述代码中,我们重新实现了touchEvent函数来处理触摸事件。根据事件类型,可以编写相应的逻辑来响应用户的触摸操作。
    3.4.3 触摸点信息
    在处理触摸事件时,我们经常需要获取触摸点的位置、ID和其他信息。可以使用QTouchEvent中的touchPoints()函数来获取所有触摸点的信息,该函数返回一个QList<QTouchPoint>类型的对象。
    cpp
    QList<QTouchPoint> touchPoints = event->touchPoints();
    foreach (const QTouchPoint &point, touchPoints) {
    __ 获取触摸点的ID
    qreal id = point.id();
    __ 获取触摸点的位置
    QPointF pos = point.pos();
    __ 获取触摸点的压力值
    qreal pressure = point.pressure();
    __ 根据触摸点的状态执行相应操作
    switch (point.state()) {
    case QTouchPoint::TouchBegan:
    __ 处理触摸点开始触摸的事件
    break;
    case QTouchPoint::TouchMoved:
    __ 处理触摸点移动的事件
    break;
    case QTouchPoint::TouchStationary:
    __ 处理触摸点静止的事件
    break;
    case QTouchPoint::TouchEnded:
    __ 处理触摸点结束触摸的事件
    break;
    }
    }
    通过上述代码,我们可以获取每个触摸点的详细信息,并根据这些信息来执行相应的处理逻辑。
    3.4.4 实战案例,绘制触摸轨迹
    在本案例中,我们将实现一个简单的应用程序,用户可以在屏幕上绘制触摸轨迹。每当触摸点移动时,我们将在屏幕上绘制一个点,以显示触摸轨迹。
    cpp
    void TouchWidget::touchEvent(QTouchEvent *event) override {
    if (event->type() == QTouchEvent::TouchUpdate) {
    QList<QTouchPoint> touchPoints = event->touchPoints();
    foreach (const QTouchPoint &point, touchPoints) {
    if (point.state() == QTouchPoint::TouchMoved) {
    __ 获取触摸点的位置并绘制
    QPointF pos = point.pos();
    QPainter painter(this);
    painter.setPen(Qt::red);
    painter.drawPoint(pos);
    __ 更新界面
    update();
    }
    }
    }
    __ 其他触摸事件处理
    QWidget::touchEvent(event);
    }
    通过上述代码,当用户在屏幕上移动触摸点时,程序将在当前位置绘制一个红色点,从而实现绘制触摸轨迹的功能。
    总结,触摸事件编程实战是Qt Widgets界面编程中的重要内容。通过掌握触摸事件类型、触摸点信息获取和实战案例,可以编写出更加友好、响应迅速的用户界面。在实际开发过程中,可以根据具体需求来实现触摸事件的处理逻辑,为用户提供更好的交互体验。

3.5 3_5_事件过滤与事件传递策略

3.5.1 3_5_事件过滤与事件传递策略

3_5_事件过滤与事件传递策略
3.5 事件过滤与事件传递策略
在Qt中,事件是应用程序交互的基础。Qt框架使用事件驱动模型,其中事件是由系统或用户生成,并由应用程序处理。在Qt Widgets编程中,事件处理的一个关键方面是事件过滤和事件传递策略。
事件过滤
事件过滤是一种机制,允许一个对象(称为过滤器)拦截并修改另一个对象(称为目标)的事件。这在某些情况下非常有用,比如当你想要在某个事件发生前先进行检查或者修改事件的处理方式时。
在Qt中,过滤器通过重写eventFilter()方法来实现。下面是一个简单的例子,展示了如何实现一个事件过滤器,
cpp
class EventFilter : public QObject {
Q_OBJECT
public:
explicit EventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
if (event->type() == QEvent::MouseButtonPress) {
__ 拦截鼠标按下事件
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
__ 处理鼠标事件…
return true; __ 处理了事件,不传递给目标对象
}
__ 默认行为,不处理事件或传递给目标对象
return QObject::eventFilter(obj, event);
}
};
要使用事件过滤器,你需要将其安装到目标对象上,并确保目标对象是过滤器的子对象或者过滤器在目标对象之前被安装。
事件传递策略
在Qt中,事件传递遵循一定的策略。当一个事件被生成后,它会按照特定的顺序传递给相关的对象。这个传递过程通常涉及以下几个步骤,

  1. 捕获阶段,事件从源对象开始,沿着继承树向上传递,直到到达最顶层的祖先或窗口。在这个过程中,事件可以被祖先对象捕获并处理。
  2. 目标阶段,事件传递到最顶层的祖先对象后,会沿着相反的路径传递到源对象。在这个过程中,事件可以被目标对象或者其子对象处理。
  3. 冒泡阶段,事件从目标对象开始,沿着继承树向上传递,直到到达窗口或最顶层的祖先。在这个过程中,事件可以被祖先对象处理。
    在Qt中,可以通过重写event()或eventFilter()方法来控制事件的处理。event()方法用于在捕获阶段和目标阶段处理事件,而eventFilter()方法用于在冒泡阶段处理事件。
    在设计事件传递策略时,需要仔细考虑事件的处理逻辑,以避免不必要的性能开销或者逻辑错误。例如,如果一个事件在冒泡阶段被拦截,那么所有该事件的后续监听器将不会被触发,这可能会导致意外的行为。
    在Qt Widgets编程中,正确地使用事件过滤和事件传递策略是实现高效且可靠用户界面交互的关键。通过深入理解事件的生命周期和传递机制,可以更好地控制应用程序的行为,并创建出既美观又响应灵敏的用户界面。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

4 QT_Widgets信号与槽机制

4.1 4_1_信号与槽机制原理

4.1.1 4_1_信号与槽机制原理

4_1_信号与槽机制原理
4.1 信号与槽机制原理
Qt的核心特性之一是其信号与槽(Signals and Slots)机制。这是一个基于事件的编程范式,用于在对象之间进行通信。在Qt中,对象(即QWidget或其子类)可以发出信号,其他对象可以连接这些信号到相应的槽函数。本节将详细介绍Qt的信号与槽机制的原理。
4.1.1 信号与槽的定义
在Qt中,信号(Signals)是一个由对象发出的消息,表明发生了一个特定的事件。槽(Slots)是与信号相对应的函数,用于处理信号引发的动作。信号和槽之间建立了一种松耦合的关系,使得对象之间的通信更为灵活和高效。
4.1.2 信号与槽的原理
Qt的信号与槽机制基于元对象系统(Meta-Object System),它提供了对象的内省能力(即对象的自描述能力)。在Qt中,每个对象都有一个元对象,它包含了对象的基本信息和与其相关的信号和槽。
当一个对象发出一个信号时,Qt的元对象系统会搜索所有连接到该信号的槽,并将它们按照优先级顺序连接起来。然后,Qt会自动调用这些槽函数,以便执行相应的操作。
4.1.3 信号与槽的优势
Qt的信号与槽机制具有以下优势,

  1. 降低耦合度,信号与槽机制使得对象之间的通信更为灵活,减少了它们之间的依赖关系。
  2. 提高可维护性,由于信号与槽建立了松耦合关系,因此修改程序时更容易维护和扩展。
  3. 提高性能,信号与槽机制在内部使用事件循环和元对象系统,可以更高效地处理对象之间的通信。
  4. 易于理解,信号与槽机制的编程模型与传统的面向对象编程模型相似,易于学习和使用。
    4.1.4 信号与槽的使用示例
    下面通过一个简单的示例来演示Qt信号与槽机制的使用,
    cpp
    __ MyWidget.h
    ifndef MYWIDGET_H
    define MYWIDGET_H
    include <QWidget>
    class MyWidget : public QWidget
    {
    Q_OBJECT
    public:
    MyWidget(QWidget *parent = nullptr);
    signals:
    void clicked();
    private slots:
    void onButtonClicked();
    private:
    QPushButton *button;
    };
    endif __ MYWIDGET_H
    __ MyWidget.cpp
    include MyWidget.h
    MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
    {
    button = new QPushButton(Click me, this);
    connect(button, &QPushButton::clicked, this, &MyWidget::onButtonClicked);
    __ 连接信号和槽
    connect(this, &MyWidget::clicked, = {
    qDebug() << Widget clicked;
    });
    }
    void MyWidget::onButtonClicked()
    {
    __ 槽函数的实现
    qDebug() << Button clicked;
    emit clicked(); __ 发出信号
    }
    在这个示例中,我们创建了一个名为MyWidget的类,它包含一个名为clicked的信号和一个名为onButtonClicked的槽函数。我们使用connect函数将按钮的clicked信号连接到MyWidget的onButtonClicked槽函数。当按钮被点击时,将执行onButtonClicked函数,并发出clicked信号。然后,我们使用connect函数将MyWidget的clicked信号连接到一个Lambda函数,该函数将在信号发出时执行。
    通过这个示例,我们可以看到Qt的信号与槽机制如何简化对象之间的通信,并提高程序的可维护性。

4.2 4_2_信号与槽连接实战

4.2.1 4_2_信号与槽连接实战

4_2_信号与槽连接实战
4.2 信号与槽连接实战
在Qt中,信号与槽的机制是实现对象间通信的核心。信号(signal)是对象发出的消息,表明发生了一个特定的事件;槽(slot)是用来响应特定信号的函数。当一个信号发出时,Qt的机制会自动寻找并执行与之相连的槽函数。
在Qt Widgets编程中,信号-槽机制是一种非常重要的特性,它让我们可以轻松地实现控件之间的交互和事件处理。下面我们通过一个简单的实例来实战连接信号与槽。
实例,一个简单的按钮点击计数器
我们将会创建一个简单的GUI应用程序,这个程序包含一个按钮和一个用来显示点击次数的标签。每当按钮被点击时,我们将会更新标签的文本。
步骤1,创建新的Qt Widgets应用项目
打开Qt Creator,创建一个新的Qt Widgets Application项目,命名为SignalAndSlotExample。
步骤2,设计界面
在mainwindow.ui文件中,从工具箱中拖拽一个QPushButton和一个QLabel到窗口中。假设你已经将它们放置在了合适的位置。
步骤3,编写信号与槽的连接代码
双击mainwindow.ui中的按钮,这将自动生成一个槽函数。在mainwindow.cpp中,找到自动生成的槽函数,并添加以下代码,
cpp
void MainWindow::on_button_clicked() {
__ 每次按钮被点击时,计数增加
++clickCount;
__ 更新标签的文本
ui->label->setText(QString(点击次数,%1).arg(clickCount));
}
on_button_clicked函数是Qt自动生成的槽函数,每当按钮被点击时,这个函数就会被调用。
步骤4,连接信号与槽
在mainwindow.cpp中,使用connect函数来连接按钮的点击信号(clicked信号)到我们创建的槽函数(on_button_clicked)。
cpp
__ 构造函数后
connect(ui->button, SIGNAL(clicked()), this, SLOT(on_button_clicked()));
这段代码中,ui->button是按钮的指针,SIGNAL(clicked())连接到了按钮的点击信号,this指针代表当前的MainWindow对象,SLOT(on_button_clicked())则是指定的槽函数。
步骤5,编译并运行
编译并运行你的程序。现在,当你点击按钮时,标签应该会显示点击次数。
通过这个简单的实例,你应该对Qt中的信号与槽机制有了更直观的理解,并学会了如何在实际项目中连接它们。在实际开发中,你可以通过连接不同的信号与槽来实现复杂的用户交互和事件处理。

4.3 4_3_信号槽的高级使用技巧

4.3.1 4_3_信号槽的高级使用技巧

4_3_信号槽的高级使用技巧
4.3 信号槽的高级使用技巧
在Qt编程中,信号槽机制是实现对象间通信的核心。它通过信号(signal)和槽(slot)的连接来保证对象间的交互和数据传递。本节将介绍一些信号槽的高级使用技巧。

  1. 信号槽的连接
    在Qt中,通过connect()函数来连接信号和槽。这个函数有两个重载版本,一个用于连接两个对象的两个信号和槽,另一个则用于连接一个信号到一个槽。
    示例,
    cpp
    QPushButton *btn = new QPushButton(点击我);
    QObject::connect(btn, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
    在上面的示例中,当按钮被点击时,会发出clicked()信号,然后调用当前对象的onBtnClicked()槽函数。
  2. 信号槽的 disconnect
    与连接信号槽相对应的是断开信号槽的连接,使用disconnect()函数可以实现。
    示例,
    cpp
    QObject::disconnect(btn, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
    这样,按钮的点击信号就不会再连接到onBtnClicked()槽上了。
  3. 信号槽的自动连接和断开
    在某些场景下,我们可能需要在特定条件下自动连接或断开信号槽。可以通过Lambda表达式来实现这一点。
    示例,
    cpp
    connect(btn, &QPushButton::clicked, ={
    __ 当条件满足时执行的代码
    __ …
    QObject::disconnect(btn, &QPushButton::clicked, this, &MyClass::onBtnClicked);
    });
  4. 信号槽的嵌套使用
    在复杂的界面编程中,可能会遇到一个信号连接到另一个槽,而这个槽又连接到另一个信号的复杂场景。这就是信号槽的嵌套使用。
    示例,
    cpp
    connect(btn1, &QPushButton::clicked, ={
    __ 执行一些操作,然后发射另一个信号
    emit anotherSignal();
    });
    connect(this, &MyClass::anotherSignal, ={
    __ 处理anotherSignal()信号
    __ …
    });
  5. 信号槽的延迟连接
    有时我们希望在某些条件满足后才连接信号和槽,这时可以使用延迟连接。
    示例,
    cpp
    connect(btn, &QPushButton::clicked, this, &MyClass::onBtnClicked, Qt::QueuedConnection);
    使用Qt::QueuedConnection连接类型,信号槽的连接会在事件循环的队列中延迟执行。
  6. 信号槽的槽函数指针
    在设计一些需要动态连接信号槽的系统时,可以使用槽函数指针来实现。
    示例,
    cpp
    connect(btn, &QPushButton::clicked, onBtnClicked);
    void MyClass::onBtnClicked() {
    __ 处理信号
    }
    在这个例子中,onBtnClicked是一个槽函数指针,它在运行时被连接到按钮的clicked信号上。
    通过以上的高级技巧,可以更加灵活地使用Qt的信号槽机制,以适应各种复杂的编程场景。这些技巧在实际的Qt开发中非常有用,希望读者能够熟练掌握并应用到实际项目中。

4.4 4_4_信号槽在多线程中的应用

4.4.1 4_4_信号槽在多线程中的应用

4_4_信号槽在多线程中的应用
4.4 信号槽在多线程中的应用
在QT中,信号槽机制是一种用于对象间通信的机制。它允许一个对象发送信号,而其他对象可以监听这些信号并作出相应的响应。这种机制在多线程编程中尤为重要,因为它可以帮助不同线程之间的对象进行有效的通信。
在多线程应用程序中,通常需要将用户界面(UI)线程与后台处理线程分开。这样做可以确保UI线程保持响应性,同时后台线程可以进行耗时的操作,如文件读写、网络请求等。在这种情况下,信号槽机制可以用于在不同线程之间传递消息。
下面是一个使用信号槽在多线程中进行通信的示例,

  1. 创建一个继承自QThread的类,用于执行后台任务。在这个类中,定义一个信号,用于向UI线程发送消息。
    cpp
    class BackgroundTask : public QThread
    {
    Q_OBJECT
    public:
    BackgroundTask(QObject *parent = nullptr) : QThread(parent)
    {
    __ 定义一个信号,用于向UI线程发送消息
    connect(this, &BackgroundTask::progressUpdate, this, &BackgroundTask::updateProgress);
    }
    signals:
    __ 定义一个信号,向UI线程发送进度更新
    void progressUpdate(const QString &message);
    public slots:
    __ 执行后台任务的槽函数
    void run()
    {
    for (int i = 0; i < 100; ++i)
    {
    __ 模拟耗时操作
    QThread::sleep(1);
    __ 发送进度更新信号
    emit progressUpdate(QString(完成进度,%1%).arg(i));
    }
    }
    private:
    __ 更新进度的槽函数
    void updateProgress(const QString &message)
    {
    __ 在这个槽函数中,可以更新UI,例如显示进度信息
    qDebug() << message;
    }
    };
  2. 在UI线程中,创建一个按钮,用于启动后台任务。同时,创建一个显示进度的标签。
    cpp
    class MainWindow : public QMainWindow
    {
    Q_OBJECT
    public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
    __ 创建一个按钮,用于启动后台任务
    QPushButton *startButton = new QPushButton(开始后台任务, this);
    startButton->setGeometry(QRect(50, 50, 100, 30));
    __ 创建一个标签,用于显示进度信息
    QLabel *progressLabel = new QLabel(进度,0%, this);
    progressLabel->setGeometry(QRect(50, 100, 100, 30));
    __ 创建一个BackgroundTask对象
    BackgroundTask *backgroundTask = new BackgroundTask(this);
    __ 连接按钮的点击信号到BackgroundTask的启动方法
    connect(startButton, &QPushButton::clicked, backgroundTask, &BackgroundTask::start);
    }
    private slots:
    __ 接收后台任务进度更新的槽函数
    void onProgressUpdate(const QString &message)
    {
    __ 更新进度标签的文本
    QLabel *progressLabel = findChild<QLabel *>(progressLabel);
    if (progressLabel)
    {
    progressLabel->setText(message);
    }
    }
    };
  3. 在main函数中,创建一个MainWindow对象,并启动应用程序。
    cpp
    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
    }
    在这个示例中,当用户点击按钮时,BackgroundTask对象会启动后台任务。在后台任务执行过程中,会不断发送进度更新信号。UI线程中的按钮和标签会根据这些信号更新界面。这种使用信号槽在多线程中进行通信的方法可以确保UI线程保持响应性,同时后台线程可以进行耗时的操作。

4.5 4_5_信号槽优化实战案例

4.5.1 4_5_信号槽优化实战案例

4_5_信号槽优化实战案例
4.5 信号槽优化实战案例
在QT中,信号和槽机制是实现事件驱动编程的关键。正确和高效地使用这一机制,对于提升程序性能和用户体验至关重要。在本节中,我们将通过一些实际的案例来探讨如何优化信号槽的使用。
案例一,避免不必要的槽函数连接
问题描述,
在开发过程中,有时我们会将信号与大量槽函数连接,尤其是当使用信号广播时,例如在QListWidget中,每个item的点击信号都连接到了同一个槽函数。
优化方案,

  • 对于常见的控件,如QListWidget,可以使用itemSelectionChanged等信号,代替每个item的点击信号。
  • 对于必须处理多个信号的情况,可以考虑使用信号过滤器(QSignalMapper)或者使用元对象系统(通过重写metaObject()函数)来减少信号连接的数量。
    案例二,减少槽函数中的开销
    问题描述,
    槽函数中可能包含大量的计算或者资源消耗的操作,这可能会导致程序运行缓慢。
    优化方案,
  • 对槽函数进行优化,避免不必要的计算和资源消耗。
  • 对于耗时的操作,可以考虑使用QThread异步执行。
  • 使用Qt的并发工具,如QFuture和QFutureWatcher,来管理和执行耗时任务。
    案例三,信号槽的性能考量
    问题描述,
    在复杂的界面中,信号和槽的连接可能非常繁杂,有时候这种复杂性会导致性能问题。
    优化方案,
  • 避免在主线程中进行耗时的操作,尤其是UI更新。
  • 对于频繁触发的信号,考虑使用信号的防抖(debounce)技术。
  • 合理使用信号的过滤和拦截机制,比如使用QObject的installEventFilter()方法。
    案例四,利用信号槽优化数据传递
    问题描述,
    在多窗口或者复杂界面结构中,数据传递往往通过信号槽来实现,但不当的数据传递方式可能会引起效率问题。
    优化方案,
  • 使用Q_EMIT来发射信号,确保信号的发送操作尽可能高效。
  • 对于大型数据传输,考虑使用序列化(如QDataStream)和事件分离技术,以减少传输频率和大小。
  • 利用QT的元对象系统(MOC),通过Q_PROPERTY宏来优化属性传递。
    通过上述案例的分析和优化,可以显著提升QT程序的性能和响应速度,同时保持代码的可读性和可维护性。在实际开发过程中,应当根据具体情况灵活运用这些优化技巧。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

5 QT_Widgets高级组件应用

5.1 5_1_树状视图组件编程实战

5.1.1 5_1_树状视图组件编程实战

5_1_树状视图组件编程实战
5.1 树状视图组件编程实战
树状视图(QTreeView)是Qt中用于显示层次结构数据的强大工具。在许多应用程序中,例如文件浏览器或组织结构的表示,树状视图都是理想的控件。本节将通过一个简单的例子来展示如何使用QTreeView和其模型来展示和操作数据。
准备工作
首先,我们需要创建一个基本的Qt项目。如果你使用的是Qt Creator,那么可以通过创建一个新的Qt Widgets Application项目来开始。确保在项目设置中选择了合适的Qt版本。
创建模型
在Qt中,树状视图使用模型-视图架构。这意味着我们需要创建一个模型来描述我们的数据以及如何访问这些数据。最常用的模型类是QStandardItemModel,它提供了一个标准的数据结构来展示树状视图。
以下是如何创建一个简单的模型并为其添加一些数据的示例,
cpp
__ 创建模型
QStandardItemModel *model = new QStandardItemModel(this);
__ 添加根节点
QStandardItem *rootItem = new QStandardItem(根节点);
model->appendRow(rootItem);
__ 添加子节点
QStandardItem *childItem1 = new QStandardItem(子节点1);
QStandardItem *childItem2 = new QStandardItem(子节点2);
rootItem->appendRow(childItem1);
rootItem->appendRow(childItem2);
__ …继续添加更多层级
创建视图
一旦模型准备就绪,我们就可以创建一个QTreeView并设置其模型。视图会使用模型来展示数据。
cpp
__ 创建树状视图
QTreeView *treeView = new QTreeView(this);
__ 设置模型
treeView->setModel(model);
__ 设置根索引使其成为展开的节点
treeView->expand(model->index(0, 0));
自定义视图
你可能希望自定义树状视图的显示方式,例如,改变项的外观或添加交互式控件。可以通过设置一个自定义的QItemDelegate来实现。
cpp
__ 创建自定义委托
class CustomDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
CustomDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
__ 绘制自定义内容…
}
};
__ 设置自定义委托
treeView->setItemDelegateForColumn(0, new CustomDelegate(this));
添加交互
我们可以添加交互式操作,如点击事件来改变树状视图中的项。为此,我们可以连接树状视图的信号。
cpp
__ 连接信号槽
connect(treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &MainWindow::onSelectionChanged);
void MainWindow::onSelectionChanged(const QItemSelection &selected,
const QItemSelection &deselected) {
if (selected.count() > 0) {
QModelIndex index = selected.first().indexes().at(0);
QString text = model->data(index).toString();
__ 处理选中项…
}
}
最终代码
下面是整个示例的代码摘要,
cpp
include <QApplication>
include <QStandardItemModel>
include <QTreeView>
include <QVBoxLayout>
include <QWidget>
class MainWindow : public QWidget {
Q_OBJECT
public:
MainWindow() {
__ 创建模型
QStandardItemModel *model = new QStandardItemModel(this);
__ 添加数据…
__ 创建视图
QTreeView *treeView = new QTreeView(this);
__ 设置模型
treeView->setModel(model);
__ 设置根索引使其成为展开的节点
treeView->expand(model->index(0, 0));
__ 自定义视图
CustomDelegate *delegate = new CustomDelegate(this);
treeView->setItemDelegateForColumn(0, delegate);
__ 添加交互
connect(treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &MainWindow::onSelectionChanged);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(treeView);
setWindowTitle(tr(树状视图实战));
}
private slots:
void onSelectionChanged(const QItemSelection &selected,
const QItemSelection &deselected) {
if (selected.count() > 0) {
QModelIndex index = selected.first().indexes().at(0);
QString text = model->data(index).toString();
__ 处理选中项…
}
}
private:
QStandardItemModel *model;
QTreeView *treeView;
};
include main.moc
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
在这个示例中,我们创建了一个简单的树状视图,展示了如何添加数据、设置模型和视图、自定义视图的外观以及响应用户的交互操作。你可以根据需要扩展这个例子,添加更多的功能和复杂性。

5.2 5_2_表格视图组件高级应用

5.2.1 5_2_表格视图组件高级应用

5_2_表格视图组件高级应用
5.2 表格视图组件高级应用
在QT中,QTableView是一个功能强大的组件,它可以用来显示和编辑表格式数据。本节将介绍一些QTableView的高级应用技巧。
5.2.1 数据模型
要使用QTableView,首先需要创建一个继承自QAbstractTableModel的数据模型。数据模型负责数据的存储和提供给视图。
cpp
class MyModel : public QAbstractTableModel
{
Q_OBJECT
public:
MyModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
__ 实现数据行数
return 0;
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
__ 实现数据列数
return 0;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
__ 实现数据提供
return QVariant();
}
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
{
__ 实现表头数据提供
return QVariant();
}
__ 实现其他必要的方法…
};
5.2.2 定制视图
QTableView提供了许多方法来自定义视图,比如设置单元格样式、编辑器、选择模式等。
cpp
myTableView->setModel(new MyModel());
myTableView->setColumnWidth(0, 200); __ 设置第一列宽度为200
myTableView->setRowHeight(0, 40); __ 设置第一行高度为40
myTableView->setSelectionBehavior(QAbstractItemView::SelectRows); __ 设置选择行为为选择整行
5.2.3 信号与槽
QTableView提供了许多信号,比如doubleClicked、clicked、itemChanged等,我们可以通过槽来响应这些信号。
cpp
connect(myTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyClass::selectionChanged);
void MyClass::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
__ 处理选择变化
}
5.2.4 虚拟列和虚拟行
有时我们可能需要动态增加列或行,这时可以使用QTableView的虚拟列和虚拟行功能。
cpp
myTableView->setColumnCount(myModel->columnCount() + 1); __ 增加一个虚拟列
myTableView->setRowCount(myModel->rowCount() + 1); __ 增加一个虚拟行
5.2.5 单元格自定义渲染
我们可以通过重写QAbstractTableModel的flags()、headerData()、data()等方法来自定义单元格的显示。此外,还可以使用QTableView的setItemDelegate()方法来设置单元格代理,进一步自定义单元格的渲染。
cpp
myTableView->setItemDelegate(new MyDelegate(this));
以上只是QTableView的一些高级应用技巧,实际上QTableView还有很多其他的功能和用法,需要我们在实际开发中不断探索和实践。

5.3 5_3_进度条与定时器组件实战

5.3.1 5_3_进度条与定时器组件实战

5_3_进度条与定时器组件实战
5.3 进度条与定时器组件实战
在QT应用中,进度条(QProgressBar)是显示进度的一个十分直观的工具。它通常用来展示操作的进度,如文件下载、大数据处理等。而定时器组件(QTimer)则可以用来周期性地执行代码,常用于需要周期性更新或者执行某些任务的情况。
5.3.1 使用QProgressBar显示进度
在使用QProgressBar时,可以通过设置其value属性来更新进度。此外,还可以使用样式表来定制进度条的外观。
cpp
__ 创建一个进度条
QProgressBar *progressBar = new QProgressBar(this);
progressBar->setGeometry(50, 50, 300, 30); __ 设置进度条的位置和大小
__ 设置最大值
progressBar->setMaximum(100);
__ 更新进度值
progressBar->setValue(10);
__ 使用定时器更新进度
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgress()));
timer->start(1000); __ 每1000ms更新一次进度
void MainWindow::updateProgress() {
static int value = 10;
if (value < progressBar->maximum()) {
value += 10;
progressBar->setValue(value);
} else {
__ 完成进度,停止定时器
timer->stop();
}
}
在上面的代码中,我们创建了一个进度条并设置了其最大值为100。然后通过连接定时器的timeout信号到一个槽函数updateProgress,来实现每秒钟更新一次进度条的值。
5.3.2 使用QTimer进行周期性操作
QTimer是Qt中用于执行周期性任务的主要工具。它通过发射timeout信号来通知周期性任务的执行。
cpp
__ 创建定时器
QTimer *timer = new QTimer(this);
__ 连接定时器的timeout信号到一个槽函数
connect(timer, SIGNAL(timeout()), this, SLOT(timerTick()));
__ 启动定时器,1000ms后执行一次
timer->start(1000);
void MainWindow::timerTick() {
__ 定时器的槽函数内容
__ 比如更新进度条的值
if (progressBar->value() < progressBar->maximum()) {
progressBar->setValue(progressBar->value() + 1);
} else {
__ 进度完成,停止定时器
timer->stop();
}
}
这段代码展示了如何使用QTimer来周期性地更新进度条。每当定时器到期,它会发出timeout信号,触发timerTick槽函数,进而更新进度条的值。
5.3.3 实战案例,文件下载进度条
在文件下载的例子中,我们可以将定时器与网络请求结合起来,以模拟下载过程,并使用进度条显示下载进度。
cpp
__ 假设这是一个网络下载类
class Downloader : public QObject {
Q_OBJECT
public:
explicit Downloader(QObject *parent = nullptr);
signals:
void downloadProgress(int percentage);
void downloadComplete();
public slots:
void startDownload(const QString &url);
private:
void updateDownloadProgress();
void downloadCompleted();
QNetworkRequest request;
QNetworkReply *reply;
int progress;
};
__ 实现Downloader类
Downloader::Downloader(QObject *parent) : QObject(parent) {
__ 初始化
}
void Downloader::startDownload(const QString &url) {
__ 设置网络请求
request.setUrl(QUrl(url));
reply = QNetworkAccessManager::instance()->get(request);
connect(reply, SIGNAL(downloadProgress(qint64, qint64)),
SLOT(updateDownloadProgress()));
connect(reply, SIGNAL(finished()), SLOT(downloadCompleted()));
}
void Downloader::updateDownloadProgress() {
__ 更新下载进度
qint64 bytesReceived = reply->bytesReceived();
qint64 bytesTotal = reply->bytesTotal();
if (bytesTotal > 0) {
__ 转换为百分比
progress = static_cast<int>(100.0 * bytesReceived _ bytesTotal);
emit downloadProgress(progress);
}
}
void Downloader::downloadCompleted() {
__ 下载完成
emit downloadComplete();
}
__ 在主窗口中使用Downloader
Downloader *downloader = new Downloader(this);
connect(downloader, SIGNAL(downloadProgress(int)),
this, SLOT(updateProgressBar(int)));
__ 开始下载
downloader->startDownload(http:__example.com_file.zip);
void MainWindow::updateProgressBar(int percentage) {
__ 更新进度条
progressBar->setValue(percentage);
}
在这个例子中,我们创建了一个Downloader类来处理文件的下载。它通过发出downloadProgress信号来通知进度,这个信号连接到主窗口的updateProgressBar槽函数,用来更新进度条。
定时器在这个例子中并不是必须的,因为QNetworkAccessManager会自动处理网络请求并通知进度。但在实际应用中,可能需要定时器来执行一些与下载过程不直接相关的周期性任务,如心跳包发送、定时检查下载状态等。

5.4 5_4_标签页组件编程技巧

5.4.1 5_4_标签页组件编程技巧

5_4_标签页组件编程技巧
5_4_标签页组件编程技巧
标签页组件是QTWidgets中一个非常有用的组件,它可以将不同的内容组织到不同的标签页中,使得用户可以方便地在多个内容之间进行切换。在本书中,我们将介绍如何使用QTabWidget来实现标签页组件,并提供一些实用的编程技巧。

  1. 创建QTabWidget对象
    要使用标签页组件,首先需要创建一个QTabWidget对象。QTabWidget是QWidget的子类,它可以容纳多个QWidget作为标签页。例如,
    cpp
    QTabWidget *tabWidget = new QTabWidget(this);
  2. 添加标签页
    可以使用addTab()方法向QTabWidget中添加新的标签页。该方法接受一个QWidget作为标签页的内容,并返回一个整数,表示该标签页的索引。例如,
    cpp
    QWidget *page1 = new QWidget();
    QWidget *page2 = new QWidget();
    tabWidget->addTab(page1, 标签页1);
    tabWidget->addTab(page2, 标签页2);
  3. 设置当前标签页
    可以使用setCurrentIndex()方法设置当前活动的标签页。例如,要设置第2个标签页为当前标签页,可以这样做,
    cpp
    tabWidget->setCurrentIndex(1);
  4. 标签页事件处理
    QTabWidget会发出一些信号,例如currentChanged(),当当前标签页发生变化时会发出这个信号。可以使用槽函数来处理这些信号。例如,
    cpp
    connect(tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onCurrentTabChanged);
    void MainWindow::onCurrentTabChanged(int index) {
    __ 处理当前标签页变化
    }
  5. 使用自定义的QWidget作为标签页
    不仅可以使用默认的QWidget作为标签页的内容,还可以使用自定义的QWidget。例如,以下代码使用了一个自定义的QWidget作为标签页的内容,
    cpp
    class CustomWidget : public QWidget {
    __ 自定义Widget的实现
    };
    CustomWidget *customWidget = new CustomWidget();
    tabWidget->addTab(customWidget, 自定义标签页);
  6. 动态添加和移除标签页
    可以使用insertTab()和removeTab()方法动态地添加和移除标签页。例如,要插入一个新的标签页,可以这样做,
    cpp
    QWidget *newPage = new QWidget();
    tabWidget->insertTab(1, newPage, 新标签页);
    要移除一个标签页,可以这样做,
    cpp
    tabWidget->removeTab(1);
  7. 优化标签页性能
    当标签页数量较多时,可能会导致性能问题。为了优化性能,可以考虑以下几点,
  • 使用QStackedWidget而不是QTabWidget,因为QStackedWidget在切换标签页时性能更好。
  • 使用QIcon而不是QPixmap作为标签页的图标,因为QIcon的加载速度更快。
  • 避免在标签页内容中使用大量的控件,以免影响性能。
    通过以上技巧,您可以更好地使用QTWidgets中的标签页组件,为用户提供更好的用户体验。

5.5 5_5_对话框组件高级编程

5.5.1 5_5_对话框组件高级编程

5_5_对话框组件高级编程
5.5 对话框组件高级编程
在QTWidgets应用程序中,对话框是用户交互的重要组成部分。它们提供了一种模态窗口,可以在处理特定任务时临时中断用户的正常流程。QT提供了多种内置对话框,如QMessageBox、QColorDialog和QFileDialog,但在很多情况下,这些对话框可能不足以满足特定的需求。这时,我们需要创建自定义对话框。
创建自定义对话框
自定义对话框通常通过继承QDialog类来实现。下面是一个简单的自定义对话框示例,
cpp
class CustomDialog : public QDialog
{
Q_OBJECT
public:
CustomDialog(QWidget *parent = nullptr);
~CustomDialog();
private slots:
void onOkButtonClicked();
void onCancelButtonClicked();
private:
QPushButton *okButton;
QPushButton *cancelButton;
};
CustomDialog::CustomDialog(QWidget *parent) : QDialog(parent)
{
__ 设置对话框的标题
setWindowTitle(tr(自定义对话框));
__ 创建按钮并设置布局
QVBoxLayout *layout = new QVBoxLayout(this);
okButton = new QPushButton(tr(确定), this);
cancelButton = new QPushButton(tr(取消), this);
layout->addWidget(okButton);
layout->addWidget(cancelButton);
__ 连接按钮的信号和槽
connect(okButton, &QPushButton::clicked, this, &CustomDialog::onOkButtonClicked);
connect(cancelButton, &QPushButton::clicked, this, &CustomDialog::onCancelButtonClicked);
}
CustomDialog::~CustomDialog()
{
}
void CustomDialog::onOkButtonClicked()
{
accept(); __ 接受对话框
}
void CustomDialog::onCancelButtonClicked()
{
reject(); __ 拒绝对话框
}
在上述代码中,我们创建了一个简单的自定义对话框,其中包含两个按钮确定和取消。当用户点击确定按钮时,对话框会被接受并通过调用accept()方法结束。相反,当用户点击取消按钮时,对话框会被拒绝并通过调用reject()方法结束。
使用对话框
创建自定义对话框后,您需要在主窗口或其他地方调用它。这通常通过实例化对话框并使用show()方法来实现。
cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
__ 创建主窗口
MainWindow mainWindow;
mainWindow.show();
__ 创建自定义对话框
CustomDialog dialog;
__ 显示对话框
if (dialog.exec() == QDialog::Accepted)
{
__ 处理确定按钮的点击
}
else
{
__ 处理取消按钮的点击
}
return app.exec();
}
在上面的代码中,我们创建了主窗口和一个自定义对话框。使用if (dialog.exec() == QDialog::Accepted)语句,我们可以检查对话框是被接受还是被拒绝。如果对话框被接受,我们可以处理相应的逻辑;如果被拒绝,我们可以处理另一个逻辑。
对话框高级编程

  1. 对话框堆叠: 在某些情况下,您可能会需要同时显示多个对话框。您可以使用QStackedWidget来堆叠多个对话框。
  2. 对话框模态: 默认情况下,对话框是非模态的,这意味着用户可以与主窗口和其他窗口进行交互。如果您需要一个模态对话框,您可以通过调用setModal(true)来设置。
  3. 对话框布局: 您可以使用各种布局来排列对话框中的控件,如QHBoxLayout、QVBoxLayout、QGridLayout等。
  4. 对话框样式: 您可以使用样式表(QSS)来自定义对话框的外观和风格。
  5. 对话框事件处理: 您可以处理各种对话框事件,如窗口最大化、窗口关闭等。
  6. 对话框动画: 您可以使用QT的动画功能为对话框添加过渡效果。
    通过这些高级编程技巧,您可以创建出更加丰富和交互性更强的对话框,从而提高用户体验。在《QT Widgets界面编程实战技巧》的后续章节中,我们将深入探讨这些高级主题。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

6 QT_Widgets界面编程进阶技巧

6.1 6_1_绘制自定义控件实战

6.1.1 6_1_绘制自定义控件实战

6_1_绘制自定义控件实战
6.1 绘制自定义控件实战
在QT中,我们可以通过继承已有控件或者直接使用QPainter来绘制自定义控件。本节将介绍如何使用QPainter绘制一个简单的自定义控件。

  1. 继承QWidget
    首先,我们需要创建一个继承自QWidget的类,这个类将负责绘制自定义控件的图形。
    cpp
    class CustomWidget : public QWidget
    {
    Q_OBJECT
    public:
    CustomWidget(QWidget *parent = nullptr);
    protected:
    void paintEvent(QPaintEvent *event) override;
    };
  2. 初始化类
    在CustomWidget的构造函数中,我们可以添加一些初始化代码。
    cpp
    CustomWidget::CustomWidget(QWidget *parent)
    : QWidget(parent)
    {
    __ 添加初始化代码
    }
  3. 绘制自定义图形
    在paintEvent函数中,我们可以使用QPainter绘制自定义图形。
    cpp
    void CustomWidget::paintEvent(QPaintEvent *event)
    {
    QPainter painter(this);
    __ 绘制自定义图形
    painter.drawRect(10, 10, 100, 100);
    }
    这段代码将在CustomWidget的中央绘制一个100x100的矩形。
  4. 编译和运行
    现在,我们可以将CustomWidget类的代码编译并运行,看看我们的自定义控件是否正常工作。
  5. 扩展
    以上代码仅作为一个简单的示例,你可以根据自己的需求,使用QPainter绘制更复杂的图形和动画。例如,你可以使用QPainter的drawLine、drawEllipse等函数绘制不同形状的图形,或者使用QPainterPath绘制路径和曲线。
    在下一节中,我们将介绍如何将自定义控件集成到我们的应用程序中,使其可以像其他QT控件一样被使用。

6.2 6_2_图片处理与显示技巧

6.2.1 6_2_图片处理与显示技巧

6_2_图片处理与显示技巧
6.2 图片处理与显示技巧
在QT Widgets应用程序中,图片处理与显示是常见的功能,QT提供了一系列丰富的类和方法来处理和显示图片。本节将介绍一些图片处理与显示的实战技巧。

  1. 使用QPixmap和QImage
    在QT中,处理图片主要使用QPixmap和QImage两个类。QPixmap类提供了图片的载入、保存、转换、裁剪、缩放等功能;QImage类则提供了对图片像素的直接访问能力,更适合进行像素级别的操作。
  2. 图片载入与保存
    使用QPixmap的load()函数可以轻松地载入图片,例如,
    cpp
    QPixmap pixmap = QPixmap(:_image_path_to_image.png);
    同样地,使用save()函数可以保存图片,
    cpp
    pixmap.save(:_image_path_to_save.png);
  3. 图片显示技巧
    在QT中,可以使用多种方式显示图片。以下是几种常见的技巧,
    3.1 使用QLabel
    QLabel是一个简单的控件,可以用来显示图片。首先,需要创建一个QLabel并设置其pixmap属性,
    cpp
    QLabel *label = new QLabel;
    label->setPixmap(QPixmap(:_image_path_to_image.png));
    3.2 使用QGraphicsView和QGraphicsPixmapItem
    如果需要更复杂的图片显示效果,可以使用QGraphicsView和QGraphicsPixmapItem。首先,创建一个QGraphicsScene,然后添加一个QGraphicsPixmapItem,
    cpp
    QGraphicsScene *scene = new QGraphicsScene;
    QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(QPixmap(:_image_path_to_image.png));
    scene->addItem(pixmapItem);
    QGraphicsView *view = new QGraphicsView(scene);
    view->show();
    3.3 使用QPushButton的setIcon()方法
    QPushButton也有一个setIcon()方法,可以用来设置按钮的图标,这个方法内部实际上是调用了setPixmap()方法,
    cpp
    QPushButton *button = new QPushButton;
    button->setIcon(QPixmap(:_image_path_to_image.png));
  4. 图片缩放技巧
    在显示图片时,经常需要对图片进行缩放。可以使用QPixmap的scaled()方法进行缩放,
    cpp
    QPixmap scaledPixmap = pixmap.scaled(label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    label->setPixmap(scaledPixmap);
  5. 图片裁剪技巧
    如果需要对图片进行裁剪,可以使用QPainter类。下面是一个简单的裁剪示例,
    cpp
    QPixmap pixmap = QPixmap(:_image_path_to_image.png);
    QPainter painter(&pixmap);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    QRect rect = QRect(10, 10, 100, 100);
    painter.drawPixmap(rect, QPixmap(:_image_path_to_image.png));
    pixmap = pixmap.copy(rect);
    以上是关于图片处理与显示技巧的一些基本介绍。在实际开发中,可以根据需要使用更高级的功能和技巧,以实现更好的用户体验。

6.3 6_3_界面元素阴影与边框效果实现

6.3.1 6_3_界面元素阴影与边框效果实现

6_3_界面元素阴影与边框效果实现
6.3 界面元素阴影与边框效果实现
在QT Widgets应用程序中,为了提升用户界面的视觉效果和用户体验,实现阴影和边框效果是常见且重要的需求。QT提供了多种方法来设置这些效果。
阴影效果实现
在QT中,要为界面元素添加阴影效果,最常用的方法是使用QGraphicsDropShadowEffect。这个效果可以为任何图形或界面元素添加阴影,从而产生立体感。下面是一个如何为QWidget添加阴影效果的示例代码,
cpp
QWidget *parentWidget = new QWidget();
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(parentWidget);
__ 设置阴影的偏移量
shadowEffect->setOffset(5, 5);
__ 设置阴影颜色和模糊 radius
shadowEffect->setColor(QColor(100, 100, 100, 100)); __ 半透明阴影
shadowEffect->setBlurRadius(10);
__ 设置阴影效果到目标 widget
parentWidget->setGraphicsEffect(shadowEffect);
在上面的代码中,setOffset 方法用来设置阴影相对于目标对象的偏移量,setColor 用来设置阴影的颜色和透明度,setBlurRadius 用来设置阴影的模糊程度。
边框效果实现
对于边框效果,QT提供了QGraphicsColorizeEffect,通过这个效果可以给图形或widget添加颜色边框。此外,还可以通过绘制路径或使用QPainter来手动绘制边框。
以下是一个使用QGraphicsColorizeEffect为QWidget添加彩色边框的例子,
cpp
QWidget *parentWidget = new QWidget();
QGraphicsColorizeEffect borderEffect = new QGraphicsColorizeEffect(parentWidget);
__ 设置边框颜色
borderEffect->setColor(QColor(255, 0, 0)); __ 红色边框
__ 应用边框效果
parentWidget->setGraphicsEffect(borderEffect);
如果需要更复杂的边框效果,例如带有渐变或图案的边框,可能需要使用QPainter来手动绘制。这将涉及创建自定义的绘制逻辑,可能还需要使用到OpenGL等更高级的图形库来实现丰富的视觉效果。
在实践中,为了更好地控制阴影和边框效果,可以在QT Creator中使用样式表(QSS,类似于CSS),通过简单的声明来改变元素的外观。例如,
css
QWidget {
border: 2px solid red; _
设置边框 _
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5); _
设置阴影 *_
}
总结来说,在QT Widgets界面编程中,实现阴影与边框效果可以通过QGraphicsEffect子类、手动绘制或使用样式表等多种方式。根据实际需求和期望的效果选择合适的方法。在设计界面时,要确保阴影和边框不会对用户操作造成干扰,并且与整体界面风格协调一致。

6.4 6_4_透明效果与渐变背景实战

6.4.1 6_4_透明效果与渐变背景实战

6_4_透明效果与渐变背景实战
6.4 透明效果与渐变背景实战
在QTWidgets应用程序中,我们可以通过设置窗口的透明度或背景渐变效果来增强用户界面的视觉效果。本节将介绍如何使用QT的绘图系统来实现这些效果。
6.4.1 透明效果
要实现窗口的透明效果,我们需要使用QWidget的setWindowOpacity函数。这个函数接受一个0到1之间的浮点数作为透明度的设置值,0表示完全透明,1表示完全不透明。
以下是一个简单示例,展示如何设置窗口的透明度,
cpp
QWidget::setWindowOpacity(0.7); __ 设置窗口透明度为70%
在实际的界面设计中,我们可以通过一个滑块控件来让用户调整透明度,如下所示,
cpp
QSlider *opacitySlider = new QSlider(Qt::Horizontal);
opacitySlider->setRange(0, 100); __ 设置滑块范围为0到100
opacitySlider->setValue(70); __ 默认设置为70%透明度
connect(opacitySlider, &QSlider::valueChanged, [=](int value) {
QWidget::setWindowOpacity(value _ 100.0);
});
在上面的代码中,我们创建了一个水平方向的QSlider滑块控件,并设置了其范围和默认值。然后,我们将滑块的值变化信号连接到一个Lambda函数上,该函数会根据滑块的当前值设置窗口的透明度。
6.4.2 渐变背景实战
为了创建一个渐变背景,我们可以使用QWidget的QPalette和QBrush。首先,我们需要创建一个自定义的QWidget子类,并在其paintEvent中绘制渐变背景。
以下是一个绘制渐变背景的示例,
cpp
class GradientWidget : public QWidget {
Q_OBJECT
public:
GradientWidget(QWidget *parent = nullptr) : QWidget(parent) {
__ 设置渐变起始和结束颜色
QColor startColor = QColor(255, 0, 0); __ 红色
QColor endColor = QColor(0, 255, 0); __ 绿色
__ 创建渐变器,并设置渐变方向为水平
QLinearGradient gradient(0, 0, width(), height());
gradient.setColorAt(0, startColor);
gradient.setColorAt(1, endColor);
__ 设置背景渐变
setPalette(QPalette(gradient));
setAutoFillBackground(true);
}
};
在上面的代码中,我们创建了一个名为GradientWidget的自定义QWidget子类。在构造函数中,我们定义了渐变的起始颜色和结束颜色,并使用QLinearGradient类来创建渐变。然后,我们使用setPalette函数将渐变应用到窗口的调色板中,并通过setAutoFillBackground(true)确保背景会被自动填充。
现在,我们可以在主窗口或其他控件中使用这个自定义的渐变控件,
cpp
GradientWidget *gradientWidget = new GradientWidget();
gradientWidget->show();
将上面的代码添加到应用程序的主窗口或其他适当的位置,就可以看到渐变的背景效果了。
通过结合使用透明效果和渐变背景,我们可以创建出更加专业和吸引人的用户界面。在实际的项目开发中,可以根据需要调整渐变的颜色、方向和位置,以及窗口的透明度,以达到最佳的视觉效果。

6.5 6_5_高级界面编程技巧分享

6.5.1 6_5_高级界面编程技巧分享

6_5_高级界面编程技巧分享
6.5 高级界面编程技巧分享
在QT Widgets界面编程中,有一些高级技巧可以帮助我们编写更加高效、易于维护的代码。在本节中,我们将分享一些高级界面编程技巧。

  1. 使用信号和槽机制进行线程通信
    在GUI应用程序中,我们经常需要进行线程通信。QT提供了信号和槽机制来解决这个问题。使用信号和槽机制,我们可以避免使用全局变量和直接操作其他线程中的对象,从而提高程序的稳定性和可维护性。
    示例代码,
    cpp
    __ MyThread.h
    ifndef MYTHREAD_H
    define MYTHREAD_H
    include <QThread>
    include <QObject>
    class MyThread : public QThread
    {
    Q_OBJECT
    public:
    explicit MyThread(QObject *parent = nullptr);
    signals:
    void mySignal(const QString &message);
    protected:
    void run() override;
    };
    endif __ MYTHREAD_H
    __ MyThread.cpp
    include MyThread.h
    MyThread::MyThread(QObject *parent) : QThread(parent)
    {
    }
    void MyThread::run()
    {
    __ 执行线程中的任务
    QString message = 这是一个信号;
    emit mySignal(message);
    }
    __ 在其他地方使用
    MyThread *thread = new MyThread();
    QObject::connect(thread, &MyThread::mySignal, this, &MyClass::mySlot);
    thread->start();
  2. 使用布局管理器优化界面布局
    QT提供了多种布局管理器,如QHBoxLayout、QVBoxLayout、QGridLayout等。使用布局管理器可以让我们更加灵活地调整界面布局,而无需关注控件的具体位置和大小。
    示例代码,
    cpp
    QHBoxLayout *layout = new QHBoxLayout();
    layout->addWidget(new QPushButton(按钮1));
    layout->addWidget(new QPushButton(按钮2));
    layout->addWidget(new QPushButton(按钮3));
    setLayout(layout);
  3. 使用QSS美化界面
    QSS(Qt Style Sheets)是一种CSS(Cascading Style Sheets)样式表的QT专用版本。通过使用QSS,我们可以方便地定制界面的样式,提高用户体验。
    示例代码,
    cpp
    __ stylesheet.qss
    QPushButton {
    background-color: ff0000;
    color: white;
    border: 1px solid ff0000;
    }
    QPushButton:hover {
    background-color: ff4444;
    }
    __ 在其他地方使用
    QApplication::setStyleSheet(QFile::read(stylesheet.qss));
  4. 使用元对象系统提高程序性能
    QT提供了元对象系统(Meta-Object System),包括信号和槽机制、对象序列化、运行时类型信息等。使用元对象系统可以提高程序性能,例如通过信号和槽机制实现线程安全的数据交换,或者使用运行时类型信息优化程序的类型检查。
    示例代码,
    cpp
    Q_ASSERT(qobject_cast<MyClass *>(obj));
    通过以上高级界面编程技巧,我们可以提高程序的性能、稳定性和可维护性。在实际开发过程中,可以根据具体需求灵活运用这些技巧,打造高质量的QT Widgets应用程序。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

免费QT视频课程 您可以看免费1000+个QT技术视频
免费QT视频课程 QT统计图和QT数据可视化视频免费看
免费QT视频课程 QT性能优化视频免费看
免费QT视频课程 QT界面美化视频免费看

7 QT_Widgets项目实战案例

7.1 7_1_桌面应用程序实战

7.1.1 7_1_桌面应用程序实战

7_1_桌面应用程序实战
7.1 桌面应用程序实战
在QTWidgets应用程序中,我们可以通过多种方式创建桌面应用程序。本节我们将介绍如何使用QTWidgets模块创建一个简单的桌面应用程序,并实现一些基本的用户界面功能。
7.1.1 创建一个QTWidgets应用程序
要创建一个QTWidgets应用程序,首先需要在QT Creator中创建一个新的QT Widgets Application项目。具体步骤如下,

  1. 打开QT Creator。
  2. 点击新建项目按钮,弹出新建项目对话框。
  3. 在左侧的项目模板列表中,选择Qt Widgets Application模板。
  4. 在右侧的项目详情区域,输入项目的名称和保存路径,例如我们将其命名为MyWidgetsApp。
  5. 选择项目的QT版本和构建套件。
  6. 点击确定按钮,QT Creator将创建一个新的QTWidgets应用程序项目。
    7.1.2 设计用户界面
    在创建好的项目中,我们可以通过QT Designer来设计用户界面。具体步骤如下,
  7. 在QT Creator中,右键点击项目文件夹,选择添加新文件。
  8. 在弹出的文件类型选择对话框中,选择Qt Designer Form作为文件类型。
  9. 点击确定按钮,QT Creator将创建一个新的QT Designer文件,命名为form.ui。
  10. 在QT Designer中,我们可以从工具箱中拖拽各种控件(如按钮、文本框、标签等)到用户界面上,并调整它们的位置和大小。
  11. 双击控件,我们可以进入控件的属性编辑界面,设置控件的属性,例如文本、颜色、字体等。
  12. 完成用户界面设计后,点击完成按钮,将设计的用户界面保存到form.ui文件中。
    7.1.3 实现应用程序逻辑
    在QT Creator中,我们可以为应用程序添加逻辑代码。具体步骤如下,
  13. 在QT Creator中,右键点击项目文件夹,选择添加新文件。
  14. 在弹出的文件类型选择对话框中,选择Qt Widgets Application作为文件类型。
  15. 在弹出的类选择对话框中,选择QMainWindow作为基类,点击下一步按钮。
  16. 输入新类的名称,例如我们将其命名为MainWindow,点击完成按钮,QT Creator将创建一个新的主窗口类。
  17. 在新创建的MainWindow类中,我们可以为控件添加事件处理函数,例如点击按钮、输入文本等操作。
  18. 在事件处理函数中,我们可以编写应用程序的逻辑代码,例如更新界面、处理用户输入等。
    7.1.4 编译和运行应用程序
    完成用户界面设计和应用程序逻辑编写后,我们可以编译和运行应用程序。具体步骤如下,
  19. 在QT Creator中,点击构建按钮,编译应用程序。
  20. 点击运行按钮,运行编译后的应用程序。
  21. 弹出的窗口即为我们在QT Designer中设计好的用户界面。我们可以点击按钮、输入文本等操作,查看应用程序的响应。
    通过以上步骤,我们就完成了一个简单的QTWidgets桌面应用程序的创建。在实际项目中,我们可以根据需求添加更多的控件和功能,实现复杂的桌面应用程序。

7.2 7_2_跨平台应用程序开发实战

7.2.1 7_2_跨平台应用程序开发实战

7_2_跨平台应用程序开发实战
7.2 跨平台应用程序开发实战
QTWidgets是QT框架的一部分,它为应用程序提供了丰富的用户界面元素。QTWidgets库支持跨平台开发,这意味着开发者可以在不同的操作系统上创建应用程序,而无需对代码进行大量的修改。本节将介绍如何使用QTWidgets进行跨平台应用程序开发实战。
7.2.1 创建跨平台项目
在QT Creator中创建跨平台项目非常简单。首先,打开QT Creator,然后点击新建项目按钮。在项目向导中,选择应用程序类别,然后选择QT Widgets应用程序。接下来,输入项目的名称和位置,选择项目的类型(例如,单个EXE文件或应用程序包),最后点击下一步按钮。
在下一个页面中,选择要使用的QT版本和构建套件。确保在设备选项中选择了通用(Universal),这样项目就可以在不同的操作系统上运行。然后点击完成按钮,QT Creator将自动为项目创建必要的文件和目录结构。
7.2.2 添加平台特定的支持
在创建项目后,需要添加对目标平台的特定支持。例如,如果您想要在Windows上创建应用程序,需要在项目中包含Windows特定的代码和资源。同样地,如果您想要在macOS或Linux上创建应用程序,需要添加相应的代码和资源。
在QT Creator中,可以通过项目属本来添加平台特定的支持。右键点击项目文件夹,然后选择属性(Properties)。在属性页中,可以找到设备(Devices)选项卡。在这个选项卡中,可以添加新的设备配置文件,并为每个配置文件指定平台特定的设置。
7.2.3 编写跨平台代码
编写跨平台代码的关键是避免使用特定平台的API和库。QTWidgets库提供了一套统一的API,可以在不同的操作系统上工作。因此,使用QTWidgets库编写跨平台代码相对容易。
下面是一个简单的跨平台应用程序示例,它创建了一个窗口并显示一条消息,
cpp
include <QApplication>
include <QMessageBox>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMessageBox::information(nullptr, 跨平台应用程序示例,
欢迎使用QTWidgets进行跨平台应用程序开发!);
return 0;
}
在这个示例中,我们使用了QApplication类来管理应用程序的生命周期,并使用QMessageBox类来显示一条消息。这些类在不同的操作系统上都可以正常工作,因此代码可以轻松地跨平台运行。
7.2.4 测试和调试跨平台应用程序
在开发跨平台应用程序时,测试和调试非常重要。QT Creator提供了一个集成的调试器,可以用来调试跨平台应用程序。
要开始调试跨平台应用程序,首先需要设置断点。在代码编辑器中,点击左侧的行号旁边的空白区域,然后点击设置断点(Set Breakpoint)按钮。接下来,点击开始调试(Start Debugging)按钮,QT Creator将启动应用程序并暂停执行在断点处。
在调试器中,可以查看变量的值、执行步进、单步执行和继续执行等操作。此外,还可以使用调试器来检查特定平台的运行情况,以确保应用程序在不同的操作系统上都能正常工作。
总之,QTWidgets库使跨平台应用程序开发变得更加容易。通过使用统一的API、添加平台特定的支持和进行充分的测试和调试,可以确保应用程序在不同的操作系统上都能提供良好的用户体验。

7.3 7_3_图形图像处理应用实战

7.3.1 7_3_图形图像处理应用实战

7_3_图形图像处理应用实战
7.3 图形图像处理应用实战
在QT中,图形图像处理是一个相当重要且实用的功能,它可以帮助我们创建出丰富多彩的应用程序。QT提供了多种图像处理类和方法,能够满足大部分图像处理的需求。

  1. QPainter绘图引擎
    QPainter是QT中用于绘图的核心类,提供了丰富的绘图接口。通过QPainter,我们可以绘制各种图形、文本、图片等。
    示例,使用QPainter绘制一个简单的图像
    cpp
    QPainter painter(this);
    painter.drawLine(10, 10, 100, 100);
    painter.drawEllipse(50, 50, 100, 100);
  2. QImage和QPixmap
    QImage和QPixmap是QT中处理图像的两个主要类。其中,QImage更注重图像的数据处理,而QPixmap则更注重图像的显示。
    示例,使用QImage和QPixmap显示一张图片
    cpp
    QImage image(:_image_test.png);
    QPixmap pixmap = QPixmap::fromImage(image);
    this->setPixmap(pixmap);
  3. 图像格式
    QT支持多种图像格式,如PNG、JPEG、BMP等。我们可以使用QImageReader和QImageWriter类来读取和写入不同格式的图像。
    示例,使用QImageReader和QImageWriter读写图像
    cpp
    QImageReader reader(:_image_test.png);
    QImage image = reader.read();
    QImageWriter writer(:_image_test_converted.png);
    writer.setImageFormat(PNG);
    writer.write(image);
  4. 图像转换
    QT提供了多种方法用于图像转换,如转换图像的颜色格式、调整图像大小、旋转和翻转图像等。
    示例,将图像转换为灰度图像
    cpp
    QImage image(:_image_test.png);
    QImage grayImage = image.convertToFormat(QImage::Format_Grayscale8);
  5. 图像处理库
    除了QT自带的图像处理功能外,我们还可以使用第三方图像处理库,如OpenCV,来进行更复杂的图像处理。
    示例,使用OpenCV进行图像处理
    cpp
    cv::Mat image = cv::imread(:_image_test.png);
    cv::Mat grayImage;
    cv::cvtColor(image, grayImage, CV_BGR2GRAY);
    cv::imshow(Grayscale Image, grayImage);
    cv::waitKey(0);
    通过以上内容的学习和实践,我们可以更好地理解和掌握QT中的图形图像处理,从而为我们的应用程序增添更多有趣和实用的功能。

7.4 7_4_数据库应用程序实战

7.4.1 7_4_数据库应用程序实战

7_4_数据库应用程序实战
7.4 数据库应用程序实战
在QT中,我们经常需要与数据库进行交互,以存储和检索数据。QT提供了强大的数据库支持,包括对SQL的支持。在本节中,我们将通过一个示例来演示如何使用QT编写一个数据库应用程序。
准备工作
首先,确保你已经安装了QT和相应的数据库管理系统(如MySQL或SQLite)。在这个例子中,我们将使用SQLite作为我们的数据库。
创建一个新的QT项目
打开QT Creator,创建一个新的QT Widgets Application项目。命名该项目为DatabaseApp。
添加数据库支持
在项目中,我们需要添加对数据库的支持。右键点击项目文件夹,选择添加新文件,然后选择Qt模块,接着选择Qt SQL。这将添加必要的头文件和库文件。
设计界面
在项目中,打开mainwindow.ui文件,设计界面。我们需要的控件包括,

  • 一个表格视图(QTableView)用于显示数据。
  • 一些按钮(QPushButton)用于添加、删除和更新数据。
    你可以使用QT Designer来拖拽这些控件到界面上。
    实现逻辑
    打开mainwindow.cpp文件,实现逻辑。
    首先,我们需要创建一个数据库连接。可以使用QSqlDatabase类来实现。以下是如何创建连接的示例代码,
    cpp
    QSqlDatabase database;
    database.setDatabaseName(DatabaseApp.db);
    if(database.open()){
    __ 数据库连接成功
    } else {
    __ 数据库连接失败
    }
    接下来,我们需要创建一个模型(QStandardItemModel)并将它与表格视图关联。模型用于存储数据,并将其展示在表格视图中。以下是如何创建模型并将其与表格视图关联的示例代码,
    cpp
    QStandardItemModel *model = new QStandardItemModel(this);
    ui->tableView->setModel(model);
    然后,我们需要为按钮添加事件处理函数。这些函数将用于添加、删除和更新数据。以下是如何为按钮添加事件处理函数的示例代码,
    cpp
    void MainWindow::on_addButton_clicked()
    {
    __ 添加数据的逻辑
    }
    void MainWindow::on_deleteButton_clicked()
    {
    __ 删除数据的逻辑
    }
    void MainWindow::on_updateButton_clicked()
    {
    __ 更新数据的逻辑
    }
    最后,我们需要实现这些事件处理函数的逻辑。例如,对于添加数据的逻辑,我们可以使用QSqlQuery类来执行SQL查询。以下是如何添加数据的示例代码,
    cpp
    void MainWindow::on_addButton_clicked()
    {
    QString name = ui->nameLineEdit->text();
    QString age = ui->ageLineEdit->text();
    QSqlQuery query;
    query.prepare(INSERT INTO People (name, age) VALUES (:name, :age));
    query.bindValue(:name, name);
    query.bindValue(:age, age);
    if(query.exec()){
    __ 数据添加成功
    } else {
    __ 数据添加失败
    }
    }
    重复类似的步骤,为删除和更新操作实现逻辑。
    测试应用程序
    编译并运行应用程序。你应该可以看到界面上的表格视图,并且可以通过按钮来添加、删除和更新数据。
    总结
    在本节中,我们通过一个示例学习了如何使用QT编写一个数据库应用程序。我们创建了一个数据库连接,使用模型来存储和展示数据,并为按钮添加了事件处理函数来实现添加、删除和更新数据的逻辑。这只是一个简单的示例,你可以根据需要扩展和修改它以满足你的应用程序需求。

7.5 7_5_网络通信应用程序实战

7.5.1 7_5_网络通信应用程序实战

7_5_网络通信应用程序实战
7.5 网络通信应用程序实战
在QT中,我们可以使用QNetwork类来实现网络通信。本节我们将通过一个实例来介绍如何使用QT编写一个简单的网络通信应用程序。
7.5.1 实例,网络下载器
本实例将实现一个简单的网络下载器,它可以下载并保存指定URL的文件内容。

  1. 创建一个新项目,命名为NetworkDownloader。
  2. 在项目中添加一个名为mainwindow.ui的UI文件,并设计界面。添加一个按钮和一个文本编辑框,分别用于开始下载和输入下载文件的URL。
  3. 双击mainwindow.ui文件,在代码编辑器中生成相应的类。
  4. 在mainwindow.cpp中实现网络下载功能。首先,我们需要包含必要的头文件,
    cpp
    include <QApplication>
    include <QFileDialog>
    include <QNetworkAccessManager>
    include <QNetworkRequest>
    include <QNetworkReply>
    include <QPushButton>
    include <QTextEdit>
    include <QVBoxLayout>
    include <QUrl>
  5. 定义一个名为NetworkDownloader的类,继承自QMainWindow。在类中,声明一个QNetworkAccessManager对象和一个QTextEdit对象,用于管理网络请求和显示下载进度,
    cpp
    class NetworkDownloader : public QMainWindow
    {
    Q_OBJECT
    public:
    NetworkDownloader(QWidget *parent = nullptr);
    ~NetworkDownloader();
    private slots:
    void downloadClicked();
    void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
    void downloadFinished();
    private:
    QNetworkAccessManager *manager;
    QTextEdit *textEdit;
    QString downloadUrl;
    };
  6. 在NetworkDownloader类的构造函数中,初始化QNetworkAccessManager对象,并设置窗口标题和UI组件,
    cpp
    NetworkDownloader::NetworkDownloader(QWidget *parent) : QMainWindow(parent)
    {
    manager = new QNetworkAccessManager(this);
    setWindowTitle(Network Downloader);
    QVBoxLayout *layout = new QVBoxLayout;
    QPushButton *downloadButton = new QPushButton(Download, this);
    QTextEdit *urlEdit = new QTextEdit(this);
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(urlEdit);
    layout->addWidget(downloadButton);
    setCentralWidget(new QWidget(this));
    QVBoxLayout *layout = new QVBoxLayout(centralWidget());
    layout->addLayout(urlEdit);
    layout->addWidget(downloadButton);
    connect(downloadButton, &QPushButton::clicked, this, &NetworkDownloader::downloadClicked);
    }
  7. 在NetworkDownloader类中实现downloadClicked槽函数。该函数将获取文本编辑框中的URL,并启动网络请求,
    cpp
    void NetworkDownloader::downloadClicked()
    {
    QString urlString = urlEdit->toPlainText();
    QUrl url(urlString);
    QNetworkRequest request(url);
    QNetworkReply *reply = manager->get(request);
    connect(reply, &QNetworkReply::downloadProgress, this, &NetworkDownloader::downloadProgress);
    connect(reply, &QNetworkReply::finished, this, &NetworkDownloader::downloadFinished);
    downloadUrl = urlString;
    }
  8. 在NetworkDownloader类中实现downloadProgress槽函数。该函数将更新文本编辑框中的内容以显示下载进度,
    cpp
    void NetworkDownloader::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
    {
    textEdit->setText(QString(Downloading %1 (%2%)).arg(downloadUrl).arg((100 * bytesReceived) _ bytesTotal));
    }
  9. 在NetworkDownloader类中实现downloadFinished槽函数。该函数将提示用户保存下载的文件,并删除网络回复对象,
    cpp
    void NetworkDownloader::downloadFinished()
    {
    QNetworkReply reply = qobject_cast<QNetworkReply >(sender());
    if (reply) {
    QString fileName = QFileDialog::getSaveFileName(this, Save File, QString(), All Files (
    );;Text Files (
    .txt));
    if (!fileName.isEmpty()) {
    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly)) {
    file.write(reply->readAll());
    file.close();
    }
    }
    reply->deleteLater();
    }
    }
  10. 在main.cpp中,添加以下代码以使用NetworkDownloader类,
    cpp
    include networkdownloader.h
    include <QApplication>
    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    NetworkDownloader window;
    window.show();
    return app.exec();
    }
  11. 编译并运行项目。现在,您可以输入一个URL并点击Download按钮来下载文件。下载进度和已完成的通知将显示在窗口中。
    注意,在实际应用中,我们需要处理更多的网络错误和异常情况,例如网络连接断开、请求超时等。您可以在downloadFinished函数中添加相应的错误处理逻辑。

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

QT界面美化视频课程
QT性能优化视频课程
QT原理与源码分析视频课程
QT QML C++扩展开发视频课程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值