在 Qt5 C++ 编程教程的这一部分中,我们将继续讨论 Qt5 小部件。 我们介绍以下小部件:QCheckBox,QListWidget,QProgressBar,QPixmap,QSplitter和QTableWidget。
QCheckBox
QCheckBox是具有两种状态的窗口小部件:开和关。 这是一个带有标签的盒子。 如果选中此复选框,则在方框中用勾号表示。
在我们的示例中,我们在窗口上显示一个复选框。 如果选中此复选框,则显示窗口标题。 否则它是隐藏的。
checkbox.h
#pragma once#include <QWidget>class CheckBox : public QWidget {Q_OBJECTpublic:CheckBox(QWidget *parent = 0);private slots:void showTitle(int);};
这是我们的代码示例的头文件。
checkbox.cpp
#include <QCheckBox>#include <QHBoxLayout>#include "checkbox.h"CheckBox::CheckBox(QWidget *parent): QWidget(parent) {QHBoxLayout *hbox = new QHBoxLayout(this);QCheckBox *cb = new QCheckBox("Show Title", this);cb->setCheckState(Qt::Checked);hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);connect(cb, &QCheckBox::stateChanged, this, &CheckBox::showTitle);}void CheckBox::showTitle(int state) {if (state == Qt::Checked) {setWindowTitle("QCheckBox");} else {setWindowTitle(" ");}}
我们在窗口上显示一个复选框,并将其连接到showTitle()槽。
cb->setCheckState(Qt::Checked);
示例开始时,该复选框已选中。
void CheckBox::showTitle(int state) {if (state == Qt::Checked) {setWindowTitle("QCheckBox");} else {setWindowTitle(" ");}}
我们确定复选框的状态,并相应地调用setWindowTitle()。
main.cpp
#include <QApplication>#include "checkbox.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);CheckBox window;window.resize(250, 150);window.setWindowTitle("QCheckBox");window.show();return app.exec();}
这是主文件。

图:QCheckBox
QListWidget
QListWidget是一个小部件,用于显示项目列表。 在我们的示例中,我们将演示如何在列表小部件中添加,重命名和删除项目。
listwidget.h
#pragma once#include <QWidget>#include <QPushButton>#include <QListWidget>class ListWidget : public QWidget {Q_OBJECTpublic:ListWidget(QWidget *parent = 0);private slots:void addItem();void renameItem();void removeItem();void clearItems();private:QListWidget *lw;QPushButton *add;QPushButton *rename;QPushButton *remove;QPushButton *removeAll;};
该示例的头文件。
listwidget.cpp
#include "listwidget.h"#include <QVBoxLayout>#include <QInputDialog>ListWidget::ListWidget(QWidget *parent): QWidget(parent) {QVBoxLayout *vbox = new QVBoxLayout();vbox->setSpacing(10);QHBoxLayout *hbox = new QHBoxLayout(this);lw = new QListWidget(this);lw->addItem("The Omen");lw->addItem("The Exorcist");lw->addItem("Notes on a scandal");lw->addItem("Fargo");lw->addItem("Capote");add = new QPushButton("Add", this);rename = new QPushButton("Rename", this);remove = new QPushButton("Remove", this);removeAll = new QPushButton("Remove All", this);vbox->setSpacing(3);vbox->addStretch(1);vbox->addWidget(add);vbox->addWidget(rename);vbox->addWidget(remove);vbox->addWidget(removeAll);vbox->addStretch(1);hbox->addWidget(lw);hbox->addSpacing(15);hbox->addLayout(vbox);connect(add, &QPushButton::clicked, this, &ListWidget::addItem);connect(rename, &QPushButton::clicked, this, &ListWidget::renameItem);connect(remove, &QPushButton::clicked, this, &ListWidget::removeItem);connect(removeAll, &QPushButton::clicked, this, &ListWidget::clearItems);setLayout(hbox);}void ListWidget::addItem() {QString c_text = QInputDialog::getText(this, "Item", "Enter new item");QString s_text = c_text.simplified();if (!s_text.isEmpty()) {lw->addItem(s_text);int r = lw->count() - 1;lw->setCurrentRow(r);}}void ListWidget::renameItem() {QListWidgetItem *curitem = lw->currentItem();int r = lw->row(curitem);QString c_text = curitem->text();QString r_text = QInputDialog::getText(this, "Item","Enter new item", QLineEdit::Normal, c_text);QString s_text = r_text.simplified();if (!s_text.isEmpty()) {QListWidgetItem *item = lw->takeItem(r);delete item;lw->insertItem(r, s_text);lw->setCurrentRow(r);}}void ListWidget::removeItem() {int r = lw->currentRow();if (r != -1) {QListWidgetItem *item = lw->takeItem(r);delete item;}}void ListWidget::clearItems(){if (lw->count() != 0) {lw->clear();}}
我们显示一个列表小部件和四个按钮。 我们将使用这些按钮在列表小部件中添加,重命名和删除项目。
lw = new QListWidget(this);lw->addItem("The Omen");lw->addItem("The Exorcist");lw->addItem("Notes on a scandal");lw->addItem("Fargo");lw->addItem("Capote);
创建QListWidget,并填充五个项目。
void ListWidget::addItem() {QString c_text = QInputDialog::getText(this, "Item", "Enter new item");QString s_text = c_text.simplified();if (!s_text.isEmpty()) {lw->addItem(s_text);int r = lw->count() - 1;lw->setCurrentRow(r);}}
addItem()方法将一个新项目添加到列表小部件。 该方法会弹出一个输入对话框。 该对话框返回一个字符串值。 我们使用simplified()方法从字符串中删除可能的空格。 如果返回的字符串不为空,则将其添加到列表末尾的列表小部件中。 最后,我们使用setCurrentRow()方法突出显示当前插入的项目。
void ListWidget::renameItem() {QListWidgetItem *curitem = lw->currentItem();int r = lw->row(curitem);QString c_text = curitem->text();QString r_text = QInputDialog::getText(this, "Item","Enter new item", QLineEdit::Normal, c_text);QString s_text = r_text.simplified();if (!s_text.isEmpty()) {QListWidgetItem *item = lw->takeItem(r);delete item;lw->insertItem(r, s_text);lw->setCurrentRow(r);}}
重命名项目包括几个步骤。 首先,我们使用currentItem()方法获取当前项目。 我们得到项目的文本和项目所在的行。 该项目的文本显示在QInputDialog对话框中。 从对话框返回的字符串由simplified()方法处理,以删除潜在的空格。 然后,我们使用takeItem()方法删除旧项目,然后将其替换为insertItem()方法。 我们删除了takeItem()方法删除的项目,因为删除的项目不再由 Qt 管理。 最后,setCurrentRow()选择新项目。
void ListWidget::removeItem() {int r = lw->currentRow();if (r != -1) {QListWidgetItem *item = lw->takeItem(r);delete item;}}
removeItem()从列表中删除特定项目。 首先,我们使用currentRow()方法获得当前选中的行。 (如果没有更多的行,则返回 -1。)使用takeItem()方法删除当前选择的项目。
void ListWidget::clearItems(){if (lw->count() != 0) {lw->clear();}}
clear()方法从列表小部件中删除所有项目。
main.cpp
#include <QApplication>#include "listwidget.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);ListWidget window;window.setWindowTitle("QListWidget");window.show();return app.exec();}
这是主文件。

图:QListWidget
QProgressBar
QProgressBar用于向用户指示操作进度。
progressbar.h
#pragma once#include <QWidget>#include <QProgressBar>#include <QPushButton>class ProgressBarEx : public QWidget {Q_OBJECTpublic:ProgressBarEx(QWidget *parent = 0);private:int progress;QTimer *timer;QProgressBar *pbar;QPushButton *startBtn;QPushButton *stopBtn;static const int DELAY = 200;static const int MAX_VALUE = 100;void updateBar();void startMyTimer();void stopMyTimer();};
该示例的头文件。
progressbar.cpp
#include <QProgressBar>#include <QTimer>#include <QGridLayout>#include "progressbar.h"ProgressBarEx::ProgressBarEx(QWidget *parent): QWidget(parent) {progress = 0;timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);QGridLayout *grid = new QGridLayout(this);grid->setColumnStretch(2, 1);pbar = new QProgressBar();grid->addWidget(pbar, 0, 0, 1, 3);startBtn = new QPushButton("Start", this);connect(startBtn, &QPushButton::clicked, this, &ProgressBarEx::startMyTimer);grid->addWidget(startBtn, 1, 0, 1, 1);stopBtn = new QPushButton("Stop", this);connect(stopBtn, &QPushButton::clicked, this, &ProgressBarEx::stopMyTimer);grid->addWidget(stopBtn, 1, 1);}void ProgressBarEx::startMyTimer() {if (progress >= MAX_VALUE) {progress = 0;pbar->setValue(0);}if (!timer->isActive()) {startBtn->setEnabled(false);stopBtn->setEnabled(true);timer->start(DELAY);}}void ProgressBarEx::stopMyTimer() {if (timer->isActive()) {startBtn->setEnabled(true);stopBtn->setEnabled(false);timer->stop();}}void ProgressBarEx::updateBar() {progress++;if (progress <= MAX_VALUE) {pbar->setValue(progress);} else {timer->stop();startBtn->setEnabled(true);stopBtn->setEnabled(false);}}
在示例中,我们有一个QProgressBar和两个按钮。 一键启动计时器,计时器依次更新进度条。 其他按钮停止计时器。
timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);
QTimer用于控制QProgressBar小部件。
pbar = new QProgressBar();
创建一个QProgressBar的实例。 默认的最小值和最大值是 0 和 100。
if (!timer->isActive()) {startBtn->setEnabled(false);stopBtn->setEnabled(true);timer->start(DELAY);}
根据进度条的状态,按钮是启用还是禁用。 这是通过setEnabled()方法完成的。
void ProgressBarEx::updateBar() {progress++;if (progress <= MAX_VALUE) {pbar->setValue(progress);} else {timer->stop();startBtn->setEnabled(true);stopBtn->setEnabled(false);}}
进度存储在progress变量中。 setValue()更新进度条的当前值。
main.cpp
#include <QApplication>#include "progressbar.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);ProgressBarEx window;window.resize(250, 150);window.setWindowTitle("QProgressBar");window.show();return app.exec();}
这是主文件。

图:QProgressBar
QPixmap
QPixmap是用于处理图像的小部件之一。 它经过优化,可在屏幕上显示图像。 在我们的代码示例中,我们将使用QPixmap在窗口上显示图像。
pixmap.h
#pragma once#include <QWidget>class Pixmap : public QWidget {public:Pixmap(QWidget *parent = 0);};
该示例的头文件。
pixmap.cpp
#include <QPixmap>#include <QLabel>#include <QHBoxLayout>#include "pixmap.h"Pixmap::Pixmap(QWidget *parent): QWidget(parent) {QHBoxLayout *hbox = new QHBoxLayout(this);QPixmap pixmap("bojnice.jpg");QLabel *label = new QLabel(this);label->setPixmap(pixmap);hbox->addWidget(label, 0, Qt::AlignTop);}
我们显示了位于斯洛伐克中部的一座著名城堡的图像。
QPixmap pixmap("bojnice.jpg");QLabel *label = new QLabel(this);label->setPixmap(pixmap);
我们创建一个像素图并将其放在标签小部件中。
main.cpp
#include <QApplication>#include "pixmap.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Pixmap window;window.setWindowTitle("QPixmap");window.show();return app.exec();}
这是主文件。
QSplitter
QSplitter允许用户通过拖动子控件之间的边界来控制子控件的大小。 在我们的示例中,我们显示了由两个拆分器组成的三个QFrame小部件。
splitter.h
#pragma once#include <QWidget>class Splitter : public QWidget {public:Splitter(QWidget *parent = 0);};
该示例的头文件。
splitter.cpp
#include <QFrame>#include <QSplitter>#include <QHBoxLayout>#include "splitter.h"Splitter::Splitter(QWidget *parent): QWidget(parent) {QHBoxLayout *hbox = new QHBoxLayout(this);QFrame *topleft = new QFrame(this);topleft->setFrameShape(QFrame::StyledPanel);QFrame *topright = new QFrame(this);topright->setFrameShape(QFrame::StyledPanel);QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);splitter1->addWidget(topleft);splitter1->addWidget(topright);QFrame *bottom = new QFrame(this);bottom->setFrameShape(QFrame::StyledPanel);QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);splitter2->addWidget(splitter1);splitter2->addWidget(bottom);QList<int> sizes({50, 100});splitter2->setSizes(sizes);hbox->addWidget(splitter2);}
在示例中,我们有三个框架小部件和两个拆分器小部件。
QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);splitter1->addWidget(topleft);splitter1->addWidget(topright);
我们创建一个拆分器小部件,并将两个框架小部件添加到拆分器中。
QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);splitter2->addWidget(splitter1);
我们还可以将拆分器添加到另一个拆分器小部件。
QList<int> sizes({50, 100});splitter2->setSizes(sizes);
使用setSizes()方法,我们设置拆分器的子窗口小部件的大小。
main.cpp
#include <QDesktopWidget>#include <QApplication>#include "splitter.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Splitter window;window.resize(350, 300);window.setWindowTitle("QSplitter");window.show();return app.exec();}
这是主文件。

图:QSplitter
在某些桌面主题中,拆分器可能无法很好地显示。
QTableWidget
QTableWidget是电子表格应用中使用的唯一窗口小部件。 (也称为网格小部件)。 它是较复杂的小部件之一。 在这里,我们仅在窗口上显示小部件。
table.h
#pragma once#include <QWidget>class Table : public QWidget {public:Table(QWidget *parent = 0);};
该示例的头文件。
table.cpp
#include <QHBoxLayout>#include <QTableWidget>#include "table.h"Table::Table(QWidget *parent): QWidget(parent) {QHBoxLayout *hbox = new QHBoxLayout(this);QTableWidget *table = new QTableWidget(25, 25, this);hbox->addWidget(table);}
该示例在窗口上显示QTableWidget。
QTableWidget *table = new QTableWidget(25, 25, this);
在这里,我们创建具有 25 行 25 列的表小部件。
main.cpp
#include <QApplication>#include "table.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Table window;window.resize(400, 250);window.setWindowTitle("QTableWidget");window.show();return app.exec();}
这是主文件。

图:QTableWidget
在本章中,我们描述了其他几个 Qt5 小部件。
