Thứ Năm, 6 tháng 5, 2021

Thiết kế hướng đối tượng | #2. Widgets - Các lớp đối tượng trong QT Creator - P1

     CHƯƠNG 2: Widget - phần 1



Trong phần này chúng ta sẽ nói về một số widget cơ bản trong Qt 5 gồm có QLabelQSliderQComboBoxQSpinBoxQLineEdit, và QMainWindow.

Widget là các phần tử cơ bản để xây dựng nên một ứng dụng GUI.  Hệ thống widget của Qt 5 rất đa dạng.

QLabel

QLabel được dùng để hiển thị văn bản và hình ảnh. Nhưng không thể tương tác với người dùng.

label.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
 
#include <QWidget>
#include <QLabel>
 
class Label : public QWidget {
 
  public:
    Label(QWidget *parent = 0);
 
  private:
    QLabel *label;
};
label.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <QVBoxLayout>
#include <QFont>
#include "label.h"
 
Label::Label(QWidget *parent)
    : QWidget(parent) {
 
  QString lyrics = "Who doesn't long for someone to hold\n\
Who knows how to love you without being told\n\
Somebody tell me why I'm on my own\n\
If there's a soulmate for everyone\n\
\n\
Here we are again, circles never end\n\
How do I find the perfect fit\n\
There's enough for everyone\n\
But I'm still waiting in line\n\
\n\
Who doesn't long for someone to hold\n\
Who knows how to love you without being told\n\
Somebody tell me why I'm on my own\n\
If there's a soulmate for everyone";
 
  label = new QLabel(lyrics, this);
  label->setFont(QFont("Comic San MS"));
 
  QVBoxLayout *vbox = new QVBoxLayout();
  vbox->addWidget(label);
  setLayout(vbox);
}

Ví dụ trên in ra lời bài hát bằng QLabel.

1
2
label = new QLabel(lyrics, this);
label->setFont(QFont("Comic San MS"));

Tạo đối tượng QLabel và thiết lập kiểu font chữ.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <QApplication>
#include <QTextStream>
#include "label.h"
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  Label window;
 
  window.setWindowTitle("QLabel");
  window.show();
 
  return app.exec();
}
Capture

QSlider

QSlider là widget hiển thị một thanh trượt có thể kéo qua kéo lại. Thường dùng để thiết lập giá trị cho một công việc nào đó.

slider.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
 
#include <QWidget>
#include <QSlider>
#include <QLabel>
 
class Slider : public QWidget {
     
  Q_OBJECT
   
  public:
    Slider(QWidget *parent = 0);
 
  private:
    QSlider *slider;
    QLabel *label;
};
slider.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <QHBoxLayout>
#include "slider.h"
 
Slider::Slider(QWidget *parent)
    : QWidget(parent) {
 
  QHBoxLayout *hbox = new QHBoxLayout(this);
          
  slider = new QSlider(Qt::Horizontal , this);
  hbox->addWidget(slider);
 
  label = new QLabel("0", this);
  hbox->addWidget(label);
 
  connect(slider, &QSlider::valueChanged, label,
    static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
}

Chúng ta cho hiển thị hai widget, một slider và một label. Slider sẽ cập nhật con số được hiển thị trên label.

1
slider = new QSlider(Qt::Horizontal , this);

Tạo một đối tượng QSlider.

1
2
connect(slider, &QSlider::valueChanged, label,
  static_cast<void (QLabel::*)(int)>(&QLabel::setNum));

Chúng ta kết nối signal valueChanged() của QSlider đến slot (phương thức) setNum().  Bản thân phương thức setNum() là một phương thức đã được overload, tức là phương thức này có nhiều prototype, mỗi prototype xử lý một kiểu dữ liệu khác nhau (hiện tại setNum() Qt 5.5.1 có hai prototype là int và double) nên chúng ta phải dùng static_cast để chỉ định đúng phương thức cần dùng.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <QApplication>
#include "slider.h"
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  Slider window;
 
  window.setWindowTitle("QSlider");
  window.show();
 
  return app.exec();
}
Capture

QComboBox

Lớp QComboBox hiển thị một danh sách các item mà user có thể chọn lựa.

combobox.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
 
#include <QWidget>
#include <QComboBox>
#include <QLabel>
 
class ComboBoxEx : public QWidget {
     
  Q_OBJECT
   
  public:
    ComboBoxEx(QWidget *parent = 0);
 
  private:
    QComboBox *combo;
    QLabel *label;
};

Chúng ta sử dụng hai widget là combobox và label.

combobox.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <QHBoxLayout>
#include "combobox.h"
 
ComboBoxEx::ComboBoxEx(QWidget *parent)
    : QWidget(parent) {
         
  QStringList distros = {"Arch", "Xubuntu", "Redhat", "Debian",
      "Mandriva"};
 
  QHBoxLayout *hbox = new QHBoxLayout(this);
          
  combo = new QComboBox();
  combo->addItems(distros);
   
  hbox->addWidget(combo);
  hbox->addSpacing(15);
 
  label = new QLabel("Arch", this);
  hbox->addWidget(label);
 
  connect(combo, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated),
      label, &QLabel::setText);
}

Trong ví dụ này, chúng ta hiển thị một combobox và item nào được chọn sẽ được hiển thị trên widget.

1
QStringList distros = {"Arch", "Xubuntu", "Redhat", "Debian", "Mandriva"};

Chúng ta dùng QStringList để lưu danh sách các chuỗi, ở đây là danh sách tên các phiên bản của hệ điều hành Linux.

1
2
combo = new QComboBox();
combo->addItems(distros);

Chúng ta tạo đối tượng QComboBox và thêm các item vào bằng phương thức addItems().

1
connect(combo, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated) label, &QLabel::setText);

Chúng ta kết nối signal activated() của lớp combobox với slot setText() của label. Cũng như ở trên, signal này cũng đã được overload nhiều prototype nên chúng ta phải dùng static_cast để chọn prototype phù hợp.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <QApplication>
#include "combobox.h"
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  ComboBoxEx window;
 
  window.resize(300, 150);
  window.setWindowTitle("QComboBox");
  window.show();
 
  return app.exec();
}
Capture

QSpinBox

QSpinbox là widget chuyên dùng để làm việc với số nguyên và các giá trị rời rạc. Ví dụ dưới đây sẽ hiển thị một spinbox chứa các số trong tập từ 0→99. Số nào được chọn thì hiển thị lên label.

spinbox.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
 
#include <QWidget>
#include <QSpinBox>
 
class SpinBox : public QWidget {
     
  Q_OBJECT
 
  public:
    SpinBox(QWidget *parent = 0);
 
  private:
    QSpinBox *spinbox;
};
spinbox.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <QHBoxLayout>
#include <QLabel>
#include "spinbox.h"
 
SpinBox::SpinBox(QWidget *parent)
    : QWidget(parent) {
         
  QHBoxLayout *hbox = new QHBoxLayout(this);  
  hbox->setSpacing(15);
     
  spinbox = new QSpinBox(this);
  QLabel *lbl = new QLabel("0", this);
 
  hbox->addWidget(spinbox); 
  hbox->addWidget(lbl);
   
  connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
    lbl, static_cast<void (QLabel::*)(int)>(&QLabel::setNum)); 
}

Chúng ta hiển thị spinbox lên window và kết nối signal valueChanged() vào slot setNum().

1
2
connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
  lbl, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));

Ở đây cả signal và slot đều được overloaded nên phải cast hai lần.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <QApplication>
#include "spinbox.h"
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  SpinBox window;
 
  window.resize(250, 150);
  window.setWindowTitle("QSpinBox");
  window.show();
 
  return app.exec();
}
Capture

QLineEdit

QLineEdit là widget cho phép gõ một dòng văn bản. Xem ví dụ.

ledit.h
1
2
3
4
5
6
7
8
9
#pragma once
 
#include <QWidget>
 
class Ledit : public QWidget {
     
  public:
    Ledit(QWidget *parent = 0);
};
ledit.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include "ledit.h"
 
Ledit::Ledit(QWidget *parent)
    : QWidget(parent) {
         
  QLabel *name = new QLabel("Name:", this);
  name->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  QLabel *age = new QLabel("Age:", this);
  age->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  QLabel *occupation = new QLabel("Occupation:", this);
  occupation->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
 
  QLineEdit *le1 = new QLineEdit(this);
  QLineEdit *le2 = new QLineEdit(this);
  QLineEdit *le3 = new QLineEdit(this);
 
  QGridLayout *grid = new QGridLayout();
 
  grid->addWidget(name, 0, 0);
  grid->addWidget(le1, 0, 1);
  grid->addWidget(age, 1, 0);
  grid->addWidget(le2, 1, 1);
  grid->addWidget(occupation, 2, 0);
  grid->addWidget(le3, 2, 1);
 
  setLayout(grid);
}

Chúng ta hiển thị ba label và ba lineEdit. Các widget này sẽ được phân bố bằng QGridLayout.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "ledit.h"
#include <QApplication>
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  Ledit window;
 
  window.setWindowTitle("QLineEdit");
  window.show();
 
  return app.exec();
}
Capture

Statusbar

Statusbar là một khu vực trên ứng dụng dùng để hiển thị một số thông tin trạng thái cho người dùng.

Trong ví dụ dưới đây, chúng ta có hai button và một statusbar. Mỗi button sẽ hiển thị một thông tin trên status bar nếu được click. Trong Qt có hai cách để hiển thị statusbar, một là dùng lớp QStatusBar, hai là dùng statusbar có sẵn trong lớp QMainWindow

statusbar.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
 
#include <QMainWindow>
#include <QPushButton>
 
class Statusbar : public QMainWindow {
     
  Q_OBJECT 
 
  public:
    Statusbar(QWidget *parent = 0);
 
  private slots:
    void OnOkPressed();
    void OnApplyPressed();
 
  private:
    QPushButton *okBtn;
    QPushButton *aplBtn;
};
statusbar.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <QLabel>
#include <QFrame>
#include <QStatusBar>
#include <QHBoxLayout>
#include "statusbar.h"
 
Statusbar::Statusbar(QWidget *parent)
    : QMainWindow(parent) {
         
  QFrame *frame = new QFrame(this);
  setCentralWidget(frame);
   
  QHBoxLayout *hbox = new QHBoxLayout(frame);
 
  okBtn = new QPushButton("OK", frame);
  hbox->addWidget(okBtn, 0, Qt::AlignLeft | Qt::AlignTop);
 
  aplBtn = new QPushButton("Apply", frame);
  hbox->addWidget(aplBtn, 1, Qt::AlignLeft | Qt::AlignTop);
 
  statusBar();
 
  connect(okBtn, &QPushButton::clicked, this, &Statusbar::OnOkPressed);
  connect(aplBtn, &QPushButton::clicked, this, &Statusbar::OnApplyPressed);
}
 
void Statusbar::OnOkPressed() {
     
  statusBar()->showMessage("OK button pressed", 2000);
}
 
void Statusbar::OnApplyPressed() {
     
 statusBar()->showMessage("Apply button pressed", 2000);
}
1
2
QFrame *frame = new QFrame(this);
setCentralWidget(frame);

Chúng ta tạo một đối tượng QFrame và đưa nó làm central widget của QMainWindow. Mỗi window chỉ chưa được một central widget.

1
2
3
4
5
okBtn = new QPushButton("OK", frame);
hbox->addWidget(okBtn, 0, Qt::AlignLeft | Qt::AlignTop);
 
aplBtn = new QPushButton("Apply", frame);
hbox->addWidget(aplBtn, 1, Qt::AlignLeft | Qt::AlignTop);

Chúng ta tạo ra hai button và đưa vào layout ngang.

1
statusBar();

Để hiển thị được statusbar thì chúng ta dùng phương thức statusBar().

1
2
3
4
void Statusbar::OnOkPressed() {
     
  statusBar()->showMessage("OK button pressed", 2000);
}

Phương thức showMessage() sẽ hiển thị thông điệp lên statusbar, tham số thứ 2 trong phưng thức này là thời gian mà thông điệp được hiển thị theo mili giây.

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <QApplication>
#include "statusbar.h"
 
int main(int argc, char *argv[]) {
     
  QApplication app(argc, argv); 
     
  Statusbar window;
 
  window.resize(300, 200);
  window.setWindowTitle("QStatusBar");
  window.show();
   
  return app.exec();
}
Capture

Không có nhận xét nào:

Đăng nhận xét

Bài tập chuỗi trong C++

  Bài tập chuỗi trong C++   (7) 668 lượt xem Chuỗi (String) trong C/C++ là một mảng ký tự được kết thúc bởi \0 (ký tự null). Dưới đây là các...