ZetCode

Qt5 小部件 II

最后修改于 2023 年 10 月 18 日

在本 Qt5 C++ 编程教程中,我们将继续讨论 Qt5 小部件。我们涵盖以下小部件:QCheckBoxQListWidgetQProgressBarQPixmapQSplitterQTableWidget

QCheckBox

QCheckBox 是一个具有两种状态的小部件:开启和关闭。它是一个带有标签的框。如果选中复选框,则由框中的一个勾号表示。

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

checkbox.h
#pragma once

#include <QWidget>

class CheckBox : public QWidget {
    
  Q_OBJECT

  public:
    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
图:QCheckBox

QListWidget

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

listwidget.h
#pragma once

#include <QWidget>
#include <QPushButton>
#include <QListWidget>

class ListWidget : public QWidget {
    
  Q_OBJECT

  public:
    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
图:QListWidget

QProgressBar

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

progressbar.h
#pragma once

#include <QWidget>
#include <QProgressBar>
#include <QPushButton>

class ProgressBarEx : public QWidget {
    
  Q_OBJECT
  
  public:
    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
图: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
图: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
图:QTableWidget

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