Daily Archives: 14/01/2016

Qt 5 C++ – Widgets 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ó QLabel, QSlider, QComboBox, QSpinBox, QLineEdit, 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.

#pragma once

#include <QWidget>
#include <QLabel>

class Label : public QWidget {

  public:
    Label(QWidget *parent = 0);

  private:
    QLabel *label;
};
#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.

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ữ.

#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 đó.

#pragma once

#include <QWidget>
#include <QSlider>
#include <QLabel>

class Slider : public QWidget {
    
  Q_OBJECT
  
  public:
    Slider(QWidget *parent = 0);

  private:
    QSlider *slider; 
    QLabel *label;
};
#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.

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

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

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.

#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.

#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.

#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.

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.

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().

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.

#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.

#pragma once

#include <QWidget>
#include <QSpinBox>

class SpinBox : public QWidget {
    
  Q_OBJECT

  public:
    SpinBox(QWidget *parent = 0);

  private:
    QSpinBox *spinbox;
};
#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().

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.

#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ụ.

#pragma once

#include <QWidget>

class Ledit : public QWidget {
    
  public:
    Ledit(QWidget *parent = 0);
};
#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.

#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

#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;
};
#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);
}
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.

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.

statusBar();

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

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.

#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

Qt 5 C++ – Event và signal

Event (sự kiện) là một phần quan trọng của bất kỳ ứng dụng GUI nào. Tất cả các ứng dụng dạng GUI xử lý event trong suốt thời gian mà nó chạy. Event phần lớn được tạo ra bởi người dùng, nhưng cũng có lúc được tạo ra bởi chính ứng dụng. Có ba thành phần tham gia vào hệ thống event:

  • Event nguồn
  • Đối tượng event
  • Event đích

Event nguồn là đối tượng tạo ra sự thay đổi. Cứ có gì đó trong ứng dụng tạo ra sự thay đổi nào đó thì nó chính là event nguồn. Đối tượng event là chính bản thân cái event đó đã được mã hóa. Event đích là đối tượng sẽ xử lý event đó.

Nếu bạn từng lập trình GUI bằng API của window, bạn đã biết là một ứng dụng GUI sau khi đã hoàn tất các công việc khởi tạo biến, đăng ký ID với hệ điều hành…v.v. thì ứng dụng đó sẽ bắt đầu một vòng lặp vô tận, vòng lặp này liên tục lắng nghe và bắt các event đang diễn ra và gửi nó đến đối tượng để xử lý bằng câu lệnh switch(). Trong Qt cũng vậy, cứ mỗi lần gọi phương thức exec() của ứng dụng thì ứng dụng sẽ bắt đầu vòng lặp của nó, tuy nhiên chúng ta không trực tiếp làm việc với vòng lặp này, mà thay vào đó chúng ta dùng hệ thống Signal & Slot của Qt, đây là một phần mở rộng của C++ và cũng là thành phần đặc trưng của riêng Qt dùng để kiểm soát event.

Nói sơ qua về cách hoạt động của cơ chế Signal & Slot, một signal (tiếng việt là tín hiệu) sẽ được phát ra khi có sự kiện nào đó diễn ra, slot là phương thức của một đối tượng nào đó, mà cứ mỗi khi chỉ có đúng signal đó được phát ra thì slot này sẽ được thực thi.

Click

Ví dụ dưới đây là một chương trình đơn giản để mô tả cách hoạt động của hệ thống event. Chương trình hiển thị một button, cứ mỗi lần click button này thì thoát chương trình.

#pragma once

#include <QWidget>

class Click : public QWidget {
    
  public:
    Click(QWidget *parent = 0);
};
#include <QPushButton>
#include <QApplication>
#include <QHBoxLayout>
#include "click.h"

Click::Click(QWidget *parent)
    : QWidget(parent) {
       
  QHBoxLayout *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);
        
  QPushButton *quitBtn = new QPushButton("Quit", this);
  hbox->addWidget(quitBtn, 0, Qt::AlignLeft | Qt::AlignTop);

  connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);
}
connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);

Phương thức connect() có tác dụng kết nối signal của đối tượng này tới slot của đối tượng khác. Trong trường hợp này nó kết nối signal clicked của button tới slot quit của qApp. 

#include <QApplication>
#include "click.h"

int main(int argc, char *argv[]) {
    
  QApplication app(argc, argv);  
    
  Click window;
  
  window.resize(250, 150);
  window.setWindowTitle("Click");
  window.show();

  return app.exec();
}
Capture

Tương tác với bàn phím – KeyPress

Ta sẽ học cách tương tác với bàn phím qua ví dụ dưới đây.

#pragma once

#include <QWidget>

class KeyPress : public QWidget {

  public:
    KeyPress(QWidget *parent = 0);

  protected:
    void keyPressEvent(QKeyEvent * e);
};
#include <QApplication>
#include <QKeyEvent>
#include "keypress.h"

KeyPress::KeyPress(QWidget *parent)
    : QWidget(parent)
{ }

void KeyPress::keyPressEvent(QKeyEvent *event) {

   if (event->key() == Qt::Key_Escape) {  
       qApp->quit();
   } 
}

Thoát chương trình khi nhấn phím Escape.

void KeyPress::keyPressEvent(QKeyEvent *e) {

   if (e->key() == Qt::Key_Escape) {  
       qApp->quit();
   } 
}

Bản thân các lớp có sẵn trong Qt đã có sẵn những slot tự động xử lý các signal riêng biệt. Tuy nhiên ta có thể code lại các slot này, trong lập trình hướng đối tượng thì khái niệm này được gọi là Overriding. Trong ví dụ này mình override lại slot keyPressEvent của lớp QWidget, slot này nhận thông tin của signal trong lớp QKeyEvent.

#include <QApplication>
#include "keypress.h"

int main(int argc, char *argv[]) {

  QApplication app(argc, argv);  
    
  KeyPress window;
  
  window.resize(250, 150);
  window.setWindowTitle("Key press");
  window.show();

  return app.exec();
}

QMoveEvent

Lớp QMoveEvent chứa các thông tin về sự thay đổi vị trí của widget. QMoveEvent sẽ tự động được gửi tới widget như keyPress ở trên.

#pragma once

#include <QMainWindow>

class Move : public QWidget {

  Q_OBJECT

  public:
    Move(QWidget *parent = 0);
 
  protected:
    void moveEvent(QMoveEvent *e);
};
#include <QMoveEvent>
#include "move.h"

Move::Move(QWidget *parent)
    : QWidget(parent)
{ }

void Move::moveEvent(QMoveEvent *e) {

  int x = e->pos().x();
  int y = e->pos().y();
  
  QString text = QString::number(x) + "," + QString::number(y);

  setWindowTitle(text);
}

Trong đoạn code trên, chúng ta xử lý sự kiện di chuyển widget. Cứ mỗi lần chúng ta di chuyển cửa sổ, một event được gửi tới slot moveEvent, cũng giống như keyPress, slot này có sẵn trong Qt và chúng ta cũng override lại nó. Chúng ta lấy vị trí tọa độ mới của widget và đưa lên thanh tiêu đề.

int x = e->pos().x();
int y = e->pos().y();

Lấy thông tin tọa độ từ đối tượng QMoveEvent.

QString text = QString::number(x) + "," + QString::number(y);

Chuyển giá trị tọa độ từ số sang chuỗi.

setWindowTitle(text);

Dùng phương thức setWindowTitle() để đặt tiêu đề cho cửa sổ.

#include <QApplication>
#include "move.h"

int main(int argc, char *argv[]) {
    
  QApplication app(argc, argv);  
    
  Move window;
  
  window.resize(250, 150);
  window.setWindowTitle("Move");
  window.show();
  
  return app.exec();
}
Capture

Ngắt kết nối signal

Nếu có kết nối signal và slot thì Qt cũng cho phép chúng ta ngắt kết nối slot với các signal đó.

#pragma once

#include <QWidget>
#include <QPushButton>

class Disconnect : public QWidget {
    
  Q_OBJECT  

  public:
    Disconnect(QWidget *parent = 0);

  private slots:
    void onClick();
    void onCheck(int);

  private:
    QPushButton *clickBtn;
};

Ở trên chúng ta khai báo hai slot. Từ khóa slot thực chất không phải của C++, mà là phần mở rộng của C++ do Qt phát triển thêm. Chúng sẽ được dịch bởi Qt trước khi được dịch bởi C++. Để có thể dùng được signal và slot trong Qt thì chúng ta phải thêm macro Q_OBJECT vào đầu mỗi khai báo lớp.

#include <QTextStream>
#include <QCheckBox>
#include <QHBoxLayout>
#include "disconnect.h"

Disconnect::Disconnect(QWidget *parent)
    : QWidget(parent) {
        
  QHBoxLayout *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);        
        
  clickBtn = new QPushButton("Click", this);
  hbox->addWidget(clickBtn, 0, Qt::AlignLeft | Qt::AlignTop);

  QCheckBox *cb = new QCheckBox("Connect", this);
  cb->setCheckState(Qt::Checked);
  hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);

  connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck);  
}

void Disconnect::onClick() {
    
  QTextStream out(stdout);
  out << "Button clicked" << endl;
}

void Disconnect::onCheck(int state) {
    
  if (state == Qt::Checked) {
    connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  } else {
    disconnect(clickBtn, &QPushButton::clicked, this, 
        &Disconnect::onClick);
  }
}

Trong ví dụ này chúng ta tạo ra một button và một checkbox. Nếu tick vào checkbox thì cho connect button với slot onClick, ngược lại thì ngắt kết nối. Cứ mỗi lần bấm button thì in ra message, tuy nhiên message này hiển thị trên console vì thế nếu bạn nên chạy chương trình từ command promtp hoặc nhìn vào cửa sổ Application Output trên Qt Creator mới thấy message.

connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck); 

Connect hai signal với hai slot.

void Disconnect::onClick() {
    
  QTextStream out(stdout);
  out << "Button clicked" << endl;
}

Nếu nhấn button thì in message.

void Disconnect::onCheck(int state) {
    
  if (state == Qt::Checked) {
    connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  } else {
    disconnect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  }
}

Slot onCheck() sẽ kết nối hoặc ngắt kết nối button với slot. Chúng ta dùng phương thức disconnect() để ngắt.

#include <QApplication>
#include "disconnect.h"

int main(int argc, char *argv[]) {
    
  QApplication app(argc, argv);  
    
  Disconnect window;
  
  window.resize(250, 150);
  window.setWindowTitle("Disconnect");
  window.show();
  
  return app.exec();
}

Capture

Timer

Timer trong Qt (hay các nền tảng khác) thương được dùng để code các công việc có tính chất lặp đi lặp lại. Trong ví dụ này ta dùng timer để hiển thị giờ hiện tại.

#pragma once

#include <QWidget>
#include <QLabel>

class Timer : public QWidget {

  public:
    Timer(QWidget *parent = 0);

  protected:
    void timerEvent(QTimerEvent *e);

  private:
    QLabel *label;
};
#include "timer.h"
#include <QHBoxLayout>
#include <QTime>

Timer::Timer(QWidget *parent)
    : QWidget(parent) {
        
  QHBoxLayout *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);               
           
  label = new QLabel("", this);
  hbox->addWidget(label, 0, Qt::AlignLeft | Qt::AlignTop);

  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);
   
  startTimer(1000);
}

void Timer::timerEvent(QTimerEvent *e) {
    
  Q_UNUSED(e);
  
  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);
}

Chúng ta hiển thị giờ từ hệ thống.

QTime qtime = QTime::currentTime();
QString stime = qtime.toString();
label->setText(stime);

Chúng ta lấy giờ hiện tại của hệ thống bằng phương thức currentTime(), sau đó chuyển nó sang kiểu chuỗi và đưa vào label.

startTimer(1000);

Phương thức startTimer() sẽ bắt đầu chu kỳ lặp của nó, cứ sau 1000ms nó sẽ phát một signal và signal đó sẽ được xử lý bởi slot timerEvent().

void Timer::timerEvent(QTimerEvent *e) {
    
  Q_UNUSED(e);
  
  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);
}

Để bắt được event từ timer, chúng ta phải override phương thức timerEvent().

#include <QApplication>
#include "timer.h"

int main(int argc, char *argv[]) {
    
  QApplication app(argc, argv);  
    
  Timer window;
  
  window.resize(250, 150);
  window.setWindowTitle("Timer");
  window.show();

  return app.exec();
}

Capture