原文: http://zetcode.com/gui/qt5/widgets2/

在 Qt5 C++ 编程教程的这一部分中,我们将继续讨论 Qt5 小部件。 我们介绍以下小部件:QCheckBoxQListWidgetQProgressBarQPixmapQSplitterQTableWidget

QCheckBox

QCheckBox是具有两种状态的窗口小部件:开和关。 这是一个带有标签的盒子。 如果选中此复选框,则在方框中用勾号表示。

在我们的示例中,我们在窗口上显示一个复选框。 如果选中此复选框,则显示窗口标题。 否则它是隐藏的。

checkbox.h

  1. #pragma once
  2. #include <QWidget>
  3. class CheckBox : public QWidget {
  4. Q_OBJECT
  5. public:
  6. CheckBox(QWidget *parent = 0);
  7. private slots:
  8. void showTitle(int);
  9. };

这是我们的代码示例的头文件。

checkbox.cpp

  1. #include <QCheckBox>
  2. #include <QHBoxLayout>
  3. #include "checkbox.h"
  4. CheckBox::CheckBox(QWidget *parent)
  5. : QWidget(parent) {
  6. QHBoxLayout *hbox = new QHBoxLayout(this);
  7. QCheckBox *cb = new QCheckBox("Show Title", this);
  8. cb->setCheckState(Qt::Checked);
  9. hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);
  10. connect(cb, &QCheckBox::stateChanged, this, &CheckBox::showTitle);
  11. }
  12. void CheckBox::showTitle(int state) {
  13. if (state == Qt::Checked) {
  14. setWindowTitle("QCheckBox");
  15. } else {
  16. setWindowTitle(" ");
  17. }
  18. }

我们在窗口上显示一个复选框,并将其连接到showTitle()槽。

  1. cb->setCheckState(Qt::Checked);

示例开始时,该复选框已选中。

  1. void CheckBox::showTitle(int state) {
  2. if (state == Qt::Checked) {
  3. setWindowTitle("QCheckBox");
  4. } else {
  5. setWindowTitle(" ");
  6. }
  7. }

我们确定复选框的状态,并相应地调用setWindowTitle()

main.cpp

  1. #include <QApplication>
  2. #include "checkbox.h"
  3. int main(int argc, char *argv[]) {
  4. QApplication app(argc, argv);
  5. CheckBox window;
  6. window.resize(250, 150);
  7. window.setWindowTitle("QCheckBox");
  8. window.show();
  9. return app.exec();
  10. }

这是主文件。

Qt5 小部件 II - 图1

图:QCheckBox

QListWidget

QListWidget是一个小部件,用于显示项目列表。 在我们的示例中,我们将演示如何在列表小部件中添加,重命名和删除项目。

listwidget.h

  1. #pragma once
  2. #include <QWidget>
  3. #include <QPushButton>
  4. #include <QListWidget>
  5. class ListWidget : public QWidget {
  6. Q_OBJECT
  7. public:
  8. ListWidget(QWidget *parent = 0);
  9. private slots:
  10. void addItem();
  11. void renameItem();
  12. void removeItem();
  13. void clearItems();
  14. private:
  15. QListWidget *lw;
  16. QPushButton *add;
  17. QPushButton *rename;
  18. QPushButton *remove;
  19. QPushButton *removeAll;
  20. };

该示例的头文件。

listwidget.cpp

  1. #include "listwidget.h"
  2. #include <QVBoxLayout>
  3. #include <QInputDialog>
  4. ListWidget::ListWidget(QWidget *parent)
  5. : QWidget(parent) {
  6. QVBoxLayout *vbox = new QVBoxLayout();
  7. vbox->setSpacing(10);
  8. QHBoxLayout *hbox = new QHBoxLayout(this);
  9. lw = new QListWidget(this);
  10. lw->addItem("The Omen");
  11. lw->addItem("The Exorcist");
  12. lw->addItem("Notes on a scandal");
  13. lw->addItem("Fargo");
  14. lw->addItem("Capote");
  15. add = new QPushButton("Add", this);
  16. rename = new QPushButton("Rename", this);
  17. remove = new QPushButton("Remove", this);
  18. removeAll = new QPushButton("Remove All", this);
  19. vbox->setSpacing(3);
  20. vbox->addStretch(1);
  21. vbox->addWidget(add);
  22. vbox->addWidget(rename);
  23. vbox->addWidget(remove);
  24. vbox->addWidget(removeAll);
  25. vbox->addStretch(1);
  26. hbox->addWidget(lw);
  27. hbox->addSpacing(15);
  28. hbox->addLayout(vbox);
  29. connect(add, &QPushButton::clicked, this, &ListWidget::addItem);
  30. connect(rename, &QPushButton::clicked, this, &ListWidget::renameItem);
  31. connect(remove, &QPushButton::clicked, this, &ListWidget::removeItem);
  32. connect(removeAll, &QPushButton::clicked, this, &ListWidget::clearItems);
  33. setLayout(hbox);
  34. }
  35. void ListWidget::addItem() {
  36. QString c_text = QInputDialog::getText(this, "Item", "Enter new item");
  37. QString s_text = c_text.simplified();
  38. if (!s_text.isEmpty()) {
  39. lw->addItem(s_text);
  40. int r = lw->count() - 1;
  41. lw->setCurrentRow(r);
  42. }
  43. }
  44. void ListWidget::renameItem() {
  45. QListWidgetItem *curitem = lw->currentItem();
  46. int r = lw->row(curitem);
  47. QString c_text = curitem->text();
  48. QString r_text = QInputDialog::getText(this, "Item",
  49. "Enter new item", QLineEdit::Normal, c_text);
  50. QString s_text = r_text.simplified();
  51. if (!s_text.isEmpty()) {
  52. QListWidgetItem *item = lw->takeItem(r);
  53. delete item;
  54. lw->insertItem(r, s_text);
  55. lw->setCurrentRow(r);
  56. }
  57. }
  58. void ListWidget::removeItem() {
  59. int r = lw->currentRow();
  60. if (r != -1) {
  61. QListWidgetItem *item = lw->takeItem(r);
  62. delete item;
  63. }
  64. }
  65. void ListWidget::clearItems(){
  66. if (lw->count() != 0) {
  67. lw->clear();
  68. }
  69. }

我们显示一个列表小部件和四个按钮。 我们将使用这些按钮在列表小部件中添加,重命名和删除项目。

  1. lw = new QListWidget(this);
  2. lw->addItem("The Omen");
  3. lw->addItem("The Exorcist");
  4. lw->addItem("Notes on a scandal");
  5. lw->addItem("Fargo");
  6. lw->addItem("Capote);

创建QListWidget,并填充五个项目。

  1. void ListWidget::addItem() {
  2. QString c_text = QInputDialog::getText(this, "Item", "Enter new item");
  3. QString s_text = c_text.simplified();
  4. if (!s_text.isEmpty()) {
  5. lw->addItem(s_text);
  6. int r = lw->count() - 1;
  7. lw->setCurrentRow(r);
  8. }
  9. }

addItem()方法将一个新项目添加到列表小部件。 该方法会弹出一个输入对话框。 该对话框返回一个字符串值。 我们使用simplified()方法从字符串中删除可能的空格。 如果返回的字符串不为空,则将其添加到列表末尾的列表小部件中。 最后,我们使用setCurrentRow()方法突出显示当前插入的项目。

  1. void ListWidget::renameItem() {
  2. QListWidgetItem *curitem = lw->currentItem();
  3. int r = lw->row(curitem);
  4. QString c_text = curitem->text();
  5. QString r_text = QInputDialog::getText(this, "Item",
  6. "Enter new item", QLineEdit::Normal, c_text);
  7. QString s_text = r_text.simplified();
  8. if (!s_text.isEmpty()) {
  9. QListWidgetItem *item = lw->takeItem(r);
  10. delete item;
  11. lw->insertItem(r, s_text);
  12. lw->setCurrentRow(r);
  13. }
  14. }

重命名项目包括几个步骤。 首先,我们使用currentItem()方法获取当前项目。 我们得到项目的文本和项目所在的行。 该项目的文本显示在QInputDialog对话框中。 从对话框返回的字符串由simplified()方法处理,以删除潜在的空格。 然后,我们使用takeItem()方法删除旧项目,然后将其替换为insertItem()方法。 我们删除了takeItem()方法删除的项目,因为删除的项目不再由 Qt 管理。 最后,setCurrentRow()选择新项目。

  1. void ListWidget::removeItem() {
  2. int r = lw->currentRow();
  3. if (r != -1) {
  4. QListWidgetItem *item = lw->takeItem(r);
  5. delete item;
  6. }
  7. }

removeItem()从列表中删除特定项目。 首先,我们使用currentRow()方法获得当前选中的行。 (如果没有更多的行,则返回 -1。)使用takeItem()方法删除当前选择的项目。

  1. void ListWidget::clearItems(){
  2. if (lw->count() != 0) {
  3. lw->clear();
  4. }
  5. }

clear()方法从列表小部件中删除所有项目。

main.cpp

  1. #include <QApplication>
  2. #include "listwidget.h"
  3. int main(int argc, char *argv[]) {
  4. QApplication app(argc, argv);
  5. ListWidget window;
  6. window.setWindowTitle("QListWidget");
  7. window.show();
  8. return app.exec();
  9. }

这是主文件。

Qt5 小部件 II - 图2

图:QListWidget

QProgressBar

QProgressBar用于向用户指示操作进度。

progressbar.h

  1. #pragma once
  2. #include <QWidget>
  3. #include <QProgressBar>
  4. #include <QPushButton>
  5. class ProgressBarEx : public QWidget {
  6. Q_OBJECT
  7. public:
  8. ProgressBarEx(QWidget *parent = 0);
  9. private:
  10. int progress;
  11. QTimer *timer;
  12. QProgressBar *pbar;
  13. QPushButton *startBtn;
  14. QPushButton *stopBtn;
  15. static const int DELAY = 200;
  16. static const int MAX_VALUE = 100;
  17. void updateBar();
  18. void startMyTimer();
  19. void stopMyTimer();
  20. };

该示例的头文件。

progressbar.cpp

  1. #include <QProgressBar>
  2. #include <QTimer>
  3. #include <QGridLayout>
  4. #include "progressbar.h"
  5. ProgressBarEx::ProgressBarEx(QWidget *parent)
  6. : QWidget(parent) {
  7. progress = 0;
  8. timer = new QTimer(this);
  9. connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);
  10. QGridLayout *grid = new QGridLayout(this);
  11. grid->setColumnStretch(2, 1);
  12. pbar = new QProgressBar();
  13. grid->addWidget(pbar, 0, 0, 1, 3);
  14. startBtn = new QPushButton("Start", this);
  15. connect(startBtn, &QPushButton::clicked, this, &ProgressBarEx::startMyTimer);
  16. grid->addWidget(startBtn, 1, 0, 1, 1);
  17. stopBtn = new QPushButton("Stop", this);
  18. connect(stopBtn, &QPushButton::clicked, this, &ProgressBarEx::stopMyTimer);
  19. grid->addWidget(stopBtn, 1, 1);
  20. }
  21. void ProgressBarEx::startMyTimer() {
  22. if (progress >= MAX_VALUE) {
  23. progress = 0;
  24. pbar->setValue(0);
  25. }
  26. if (!timer->isActive()) {
  27. startBtn->setEnabled(false);
  28. stopBtn->setEnabled(true);
  29. timer->start(DELAY);
  30. }
  31. }
  32. void ProgressBarEx::stopMyTimer() {
  33. if (timer->isActive()) {
  34. startBtn->setEnabled(true);
  35. stopBtn->setEnabled(false);
  36. timer->stop();
  37. }
  38. }
  39. void ProgressBarEx::updateBar() {
  40. progress++;
  41. if (progress <= MAX_VALUE) {
  42. pbar->setValue(progress);
  43. } else {
  44. timer->stop();
  45. startBtn->setEnabled(true);
  46. stopBtn->setEnabled(false);
  47. }
  48. }

在示例中,我们有一个QProgressBar和两个按钮。 一键启动计时器,计时器依次更新进度条。 其他按钮停止计时器。

  1. timer = new QTimer(this);
  2. connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);

QTimer用于控制QProgressBar小部件。

  1. pbar = new QProgressBar();

创建一个QProgressBar的实例。 默认的最小值和最大值是 0 和 100。

  1. if (!timer->isActive()) {
  2. startBtn->setEnabled(false);
  3. stopBtn->setEnabled(true);
  4. timer->start(DELAY);
  5. }

根据进度条的状态,按钮是启用还是禁用。 这是通过setEnabled()方法完成的。

  1. void ProgressBarEx::updateBar() {
  2. progress++;
  3. if (progress <= MAX_VALUE) {
  4. pbar->setValue(progress);
  5. } else {
  6. timer->stop();
  7. startBtn->setEnabled(true);
  8. stopBtn->setEnabled(false);
  9. }
  10. }

进度存储在progress变量中。 setValue()更新进度条的当前值。

main.cpp

  1. #include <QApplication>
  2. #include "progressbar.h"
  3. int main(int argc, char *argv[]) {
  4. QApplication app(argc, argv);
  5. ProgressBarEx window;
  6. window.resize(250, 150);
  7. window.setWindowTitle("QProgressBar");
  8. window.show();
  9. return app.exec();
  10. }

这是主文件。

Qt5 小部件 II - 图3

图:QProgressBar

QPixmap

QPixmap是用于处理图像的小部件之一。 它经过优化,可在屏幕上显示图像。 在我们的代码示例中,我们将使用QPixmap在窗口上显示图像。

pixmap.h

  1. #pragma once
  2. #include <QWidget>
  3. class Pixmap : public QWidget {
  4. public:
  5. Pixmap(QWidget *parent = 0);
  6. };

该示例的头文件。

pixmap.cpp

  1. #include <QPixmap>
  2. #include <QLabel>
  3. #include <QHBoxLayout>
  4. #include "pixmap.h"
  5. Pixmap::Pixmap(QWidget *parent)
  6. : QWidget(parent) {
  7. QHBoxLayout *hbox = new QHBoxLayout(this);
  8. QPixmap pixmap("bojnice.jpg");
  9. QLabel *label = new QLabel(this);
  10. label->setPixmap(pixmap);
  11. hbox->addWidget(label, 0, Qt::AlignTop);
  12. }

我们显示了位于斯洛伐克中部的一座著名城堡的图像。

  1. QPixmap pixmap("bojnice.jpg");
  2. QLabel *label = new QLabel(this);
  3. label->setPixmap(pixmap);

我们创建一个像素图并将其放在标签小部件中。

main.cpp

  1. #include <QApplication>
  2. #include "pixmap.h"
  3. int main(int argc, char *argv[]) {
  4. QApplication app(argc, argv);
  5. Pixmap window;
  6. window.setWindowTitle("QPixmap");
  7. window.show();
  8. return app.exec();
  9. }

这是主文件。

QSplitter

QSplitter允许用户通过拖动子控件之间的边界来控制子控件的大小。 在我们的示例中,我们显示了由两个拆分器组成的三个QFrame小部件。

splitter.h

  1. #pragma once
  2. #include <QWidget>
  3. class Splitter : public QWidget {
  4. public:
  5. Splitter(QWidget *parent = 0);
  6. };

该示例的头文件。

splitter.cpp

  1. #include <QFrame>
  2. #include <QSplitter>
  3. #include <QHBoxLayout>
  4. #include "splitter.h"
  5. Splitter::Splitter(QWidget *parent)
  6. : QWidget(parent) {
  7. QHBoxLayout *hbox = new QHBoxLayout(this);
  8. QFrame *topleft = new QFrame(this);
  9. topleft->setFrameShape(QFrame::StyledPanel);
  10. QFrame *topright = new QFrame(this);
  11. topright->setFrameShape(QFrame::StyledPanel);
  12. QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);
  13. splitter1->addWidget(topleft);
  14. splitter1->addWidget(topright);
  15. QFrame *bottom = new QFrame(this);
  16. bottom->setFrameShape(QFrame::StyledPanel);
  17. QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);
  18. splitter2->addWidget(splitter1);
  19. splitter2->addWidget(bottom);
  20. QList<int> sizes({50, 100});
  21. splitter2->setSizes(sizes);
  22. hbox->addWidget(splitter2);
  23. }

在示例中,我们有三个框架小部件和两个拆分器小部件。

  1. QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);
  2. splitter1->addWidget(topleft);
  3. splitter1->addWidget(topright);

我们创建一个拆分器小部件,并将两个框架小部件添加到拆分器中。

  1. QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);
  2. splitter2->addWidget(splitter1);

我们还可以将拆分器添加到另一个拆分器小部件。

  1. QList<int> sizes({50, 100});
  2. splitter2->setSizes(sizes);

使用setSizes()方法,我们设置拆分器的子窗口小部件的大小。

main.cpp

  1. #include <QDesktopWidget>
  2. #include <QApplication>
  3. #include "splitter.h"
  4. int main(int argc, char *argv[]) {
  5. QApplication app(argc, argv);
  6. Splitter window;
  7. window.resize(350, 300);
  8. window.setWindowTitle("QSplitter");
  9. window.show();
  10. return app.exec();
  11. }

这是主文件。

Qt5 小部件 II - 图4

图:QSplitter

在某些桌面主题中,拆分器可能无法很好地显示。

QTableWidget

QTableWidget是电子表格应用中使用的唯一窗口小部件。 (也称为网格小部件)。 它是较复杂的小部件之一。 在这里,我们仅在窗口上显示小部件。

table.h

  1. #pragma once
  2. #include <QWidget>
  3. class Table : public QWidget {
  4. public:
  5. Table(QWidget *parent = 0);
  6. };

该示例的头文件。

table.cpp

  1. #include <QHBoxLayout>
  2. #include <QTableWidget>
  3. #include "table.h"
  4. Table::Table(QWidget *parent)
  5. : QWidget(parent) {
  6. QHBoxLayout *hbox = new QHBoxLayout(this);
  7. QTableWidget *table = new QTableWidget(25, 25, this);
  8. hbox->addWidget(table);
  9. }

该示例在窗口上显示QTableWidget

  1. QTableWidget *table = new QTableWidget(25, 25, this);

在这里,我们创建具有 25 行 25 列的表小部件。

main.cpp

  1. #include <QApplication>
  2. #include "table.h"
  3. int main(int argc, char *argv[]) {
  4. QApplication app(argc, argv);
  5. Table window;
  6. window.resize(400, 250);
  7. window.setWindowTitle("QTableWidget");
  8. window.show();
  9. return app.exec();
  10. }

这是主文件。

Qt5 小部件 II - 图5

图:QTableWidget

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