joi, 7 mai 2020

Qt - Group Box-uri cu layout.

Buna ziua,



Haideti inapoi in laboratorul de Qt
sa vedem cum au facut programatorii de la Nokia si/sau Digia - aceiasi sunt, o lectie despre butoane puse in niste GroupBox-uri la randul lor puse intr-un layout.


Nota: Daca ati cautat cursul din C11, el este pe pagina anterioara acesteia.


Impartirea proiectului in fisiere si clase:
 - un program main.cpp clasic care instantiaza clasa ferestrei principale definita mai jos.
 - o declaratie a clasei ferestrei principale: window.h
 - o implementare a clasei ferestrei principale: window.cpp
  
PROGRAMUL PRINCIPAL

Creati main.cpp-ul absolut clasic:

Programul principal include clasa noastra window.h

Sursa:

#include <QApplication>

#include "window.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Window window;
    window.show();
    return app.exec();
}


DECLARATIA CLASEI DE FEREASTRA


Sursa:

#ifndef WINDOW_H
#define WINDOW_H

#include <QWidget>

QT_BEGIN_NAMESPACE
class QGroupBox;
QT_END_NAMESPACE

//! [0]
class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = 0);

private:
    QGroupBox *createFirstExclusiveGroup();
    QGroupBox *createSecondExclusiveGroup();
    QGroupBox *createNonExclusiveGroup();
    QGroupBox *createPushButtonGroup();
};
//! [0]

#endif

Comentarii la setul [0] de linii de cod:
- este o clasa banala, numita Window, derivata public din QWidget, deci are tot ce are QWidget, inclusiv geometrie etc.
- Macroul Q_OBJECT ne spune ca este o clasa cu sloturi si semnale sau ca va fi o clasa cu sloturi si semnale in viitor, daca o mai dezvoltam.
- Constructorul este cel care realizeaza propriuzis fereastra, in codul lui se vor programa construirile tuturor elementelor: layout-ul, (adica schema aceea de cutie cu globuri de craciun, impartita in patrate), GroupBox-urile - remarcati ca anuntam ca vom folosi acea clasa !, restul.
- class QGroupBox; este un fel de declaratie in avans, care e mai rapida la compilare decat includerea clasei cu #include.
- sunt patru metode mari ale obiectului Window, rolul lor este sa construiasca , probabil, portiuni din obiect. Cand constructorul ar fi foarte se poate imparti asa in parti semnificative, si relativ independente. Ele pot fi si programate si testate separat.

In practica n-ar fi rau sa le comentati, cu  // in fata,  pe ultimele 3 cat scrieti doar codul primeia, ca sa puteti testa cum functioneaza prima parte:

private:
    QGroupBox *createFirstExclusiveGroup();
    //  QGroupBox *createSecondExclusiveGroup();
    //  QGroupBox *createNonExclusiveGroup();
    //  QGroupBox *createPushButtonGroup();

Nota: Aceste functii chiar construiesc partile din obiect si returneaza pointeri la ele, ca un fel de new mai evoluat. Acest lucru va conta la implementare.

Sfarsit de comentarii la setul [0] de linii de cod:


Fisierul Windows.cpp, complet:

#include <QtWidgets>

#include "window.h"

//! [0]
Window::Window(QWidget *parent)
    : QWidget(parent)
{
    QGridLayout *grid = new QGridLayout;
    grid->addWidget(createFirstExclusiveGroup(), 0, 0);
    grid->addWidget(createSecondExclusiveGroup(), 1, 0);
    grid->addWidget(createNonExclusiveGroup(), 0, 1);
    grid->addWidget(createPushButtonGroup(), 1, 1);
    setLayout(grid);

    setWindowTitle(tr("Group Boxes"));
    resize(480, 320);
}
//! [0]

//! [1]
QGroupBox *Window::createFirstExclusiveGroup()
{
//! [2]
    QGroupBox *groupBox = new QGroupBox(tr("Exclusive Radio Buttons"));

    QRadioButton *radio1 = new QRadioButton(tr("&Radio button 1"));
    QRadioButton *radio2 = new QRadioButton(tr("R&adio button 2"));
    QRadioButton *radio3 = new QRadioButton(tr("Ra&dio button 3"));

    radio1->setChecked(true);
//! [1] //! [3]

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(radio1);
    vbox->addWidget(radio2);
    vbox->addWidget(radio3);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);
//! [2]

    return groupBox;
}
//! [3]

//! [4]
QGroupBox *Window::createSecondExclusiveGroup()
{
    QGroupBox *groupBox = new QGroupBox(tr("E&xclusive Radio Buttons"));
    groupBox->setCheckable(true);
    groupBox->setChecked(false);
//! [4]

//! [5]
    QRadioButton *radio1 = new QRadioButton(tr("Rad&io button 1"));
    QRadioButton *radio2 = new QRadioButton(tr("Radi&o button 2"));
    QRadioButton *radio3 = new QRadioButton(tr("Radio &button 3"));
    radio1->setChecked(true);
    QCheckBox *checkBox = new QCheckBox(tr("Ind&ependent checkbox"));
    checkBox->setChecked(true);
//! [5]

//! [6]
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(radio1);
    vbox->addWidget(radio2);
    vbox->addWidget(radio3);
    vbox->addWidget(checkBox);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);

    return groupBox;
}
//! [6]

//! [7]
QGroupBox *Window::createNonExclusiveGroup()
{
    QGroupBox *groupBox = new QGroupBox(tr("Non-Exclusive Checkboxes"));
    groupBox->setFlat(true);
//! [7]

//! [8]
    QCheckBox *checkBox1 = new QCheckBox(tr("&Checkbox 1"));
    QCheckBox *checkBox2 = new QCheckBox(tr("C&heckbox 2"));
    checkBox2->setChecked(true);
    QCheckBox *tristateBox = new QCheckBox(tr("Tri-&state button"));
    tristateBox->setTristate(true);
//! [8]
    tristateBox->setCheckState(Qt::PartiallyChecked);

//! [9]
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(checkBox1);
    vbox->addWidget(checkBox2);
    vbox->addWidget(tristateBox);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);

    return groupBox;
}
//! [9]

//! [10]
QGroupBox *Window::createPushButtonGroup()
{
    QGroupBox *groupBox = new QGroupBox(tr("&Push Buttons"));
    groupBox->setCheckable(true);
    groupBox->setChecked(true);
//! [10]

//! [11]
    QPushButton *pushButton = new QPushButton(tr("&Normal Button"));
    QPushButton *toggleButton = new QPushButton(tr("&Toggle Button"));
    toggleButton->setCheckable(true);
    toggleButton->setChecked(true);
    QPushButton *flatButton = new QPushButton(tr("&Flat Button"));
    flatButton->setFlat(true);
//! [11]

//! [12]
    QPushButton *popupButton = new QPushButton(tr("Pop&up Button"));
    QMenu *menu = new QMenu(this);
    menu->addAction(tr("&First Item"));
    menu->addAction(tr("&Second Item"));
    menu->addAction(tr("&Third Item"));
    menu->addAction(tr("F&ourth Item"));
    popupButton->setMenu(menu);
//! [12]

    QAction *newAction = menu->addAction(tr("Submenu"));
    QMenu *subMenu = new QMenu(tr("Popup Submenu"));
    subMenu->addAction(tr("Item 1"));
    subMenu->addAction(tr("Item 2"));
    subMenu->addAction(tr("Item 3"));
    newAction->setMenu(subMenu);

//! [13]
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(pushButton);
    vbox->addWidget(toggleButton);
    vbox->addWidget(flatButton);
    vbox->addWidget(popupButton);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);

    return groupBox;
}
//! [13]

Sfarsitul fisierul Windows.cpp. 


Comentariile pe sectiuni:


In imagine: sectiunea [0]

Comentariile sectiunii [0]:
- clasa Windows e derivata din QWidget, iar constructorul ei va face si initializarea partii mostenite, apeland constructorul clasei QWidget.
Asa se explica acel: ": QWidget(parent)".
- in general se pot folosi aceiasi parametri, daca convin, in acest caz pointerul la obiectul parinte.
- In acolada constructorului sunt instructiuni:
-- Se instantiaza un QGridLayout, pointerul la el, returnat de new este grid.
-- Acest grid, fiind din clasa QGridLayout, poseda metoda pentru a adauga alte obiecet cu adrese cunoscute, in layout. Se numeste addWidget().
-- Layout-ul grila este impartit in patru parti, A, B, C, D. Parametrii 0 sau 1 sunt linia si coloana din matrice, B este pe pozitia 1,0 deci aranjarea e ca mai jos:
  
  |  0    1

-------------
0|  A   C            C = nonExclusievGroup        
1|  B   D            B = SecondExclusiveGroup


Fiecare addWidget adauga in grila in pozitia indicata obiectul creat la apel. Exemplu: grid->addWidget(createNonExclusiveGroup(), 0, 1);
adauga in grila obiectul din pozitia C, din dreapta sus. rand=0 coloana=1.


-i se pune ferestrei titlu, care poate fi tradus in viitor, de aici tr().
-se redimensioneaza fereastra.

Crearea grupului A: Primul grup exclusiv, comentarii [1]-[3]


- se creaza un GroupBox si trei radio butoane.
- primul radio buton este selectat: setChecked(). metoda e pe lista in doc clasei.
- deocamdata butoanele "plutesc in cutie"
- dar le vom aseza vertical intr-un VBoxLayout.
- si intregului grup ii aplicam layout-ul, astfel ca grupul se va prezenta organizat. [2] final.
- returnam adresa grupului nou creat.

Daca ar fi singur, grupul ar arata asa:


Crearea grupului B: Al doilea grup exclusiv, comentarii [4]-[6]
- si aici am un QGroupBox cu nume traductibil si tasta X pentru actionare
- grupul are propiretatea Checkable = true deci este activabil cu checkbox.
- grupul are proprietatea Checked = false , deci activarea sa este oprita, grupul este inactiv.
(Remarcati ca acest QGroupBox este cumva mai istet decat QButtonGroup).
- sunt create 3 radio butoane, cu nume traductibile si se sugereaza ca se vor putea actiona cu taste diferite:  i,o,b
- primul radio buton e actionat
- e creat si un checkbox
- care este deja bifat
- pentru aranjare este creat un layout vertical: QVBoxLayout
- in layout sunt aranjate radio butoanele si checkbox-ul
- addStretch adauga un QSpacerItem, un fel de arculet care se extinde pe restul spatiului.
- se ataseaza groupbox-ului layout-ul, adica se ordoneaza frumos vertical ce este asezat  in groupbox.
- se returneaza adresa groupbox-ului.

 Daca ar fi singur, al doilea grup, pozitia B, ar arata asa:


Crearea grupului C: Al treilea grup nonexclusiv, comentarii [7]-[9]

- este creat un QGroupBox
- acesta are atributul "flat" ca sa nu arate ca un basorelief pe anumite stiluri. Hm.
- am si trei check-box-uri: checkBox1,checkBox2,tristateBox
- al doilea este bifat
- al treilea este intr-o faza intermediara, nici bifat nici nebifat (are un patrat in mijloc) cel putin pe acest stil.
- avem si un layout vertical
- in care sunt puse checkbox-urile si un arculetz.
- se returneaza adresa grupului.

 Daca ar fi singur, al treilea grup, pozitia C, ar arata asa:

Crearea grupului D: Al patrulea grup nonexclusiv, comentarii [10]-[13]
- un groupbox cu check-box de activare [10]
- in grup e un prim buton normal
- al doilea buton, normal, este transformat in ToggleButton, ceea ce se face tratandu-l ca pe un checkbox ! Il facem sa aiba bit on,off si sa fie on.

toggleButton->setCheckable(true);
toggleButton->setChecked(true);


- al trilea buton este aplatizat. Chiar asa arata.
- dintr-un buton pot sa fac un Popup Button, tot cu un truc:
--- creez intai un meniu
--- si ii setez,ii atasez butonului un meniu [12]-[12]

 QMenu *menu = new QMenu(this);
menu->addAction(tr("&First Item"));
menu->addAction(tr("&Second Item"));
menu->addAction(tr("&Third Item"));
menu->addAction(tr("F&ourth Item"));
popupButton->setMenu(menu);

....
Daca vreau si un submeniu, procedez ca la meniuri, adica
  adaug o noua actiune in meniul vechi, creez un submeniu in care pun cateva
 randuri iar noii actiuni din primul meniu ii atasez submeniul, vezi finalul
 sectiunii [12]-[13].

- in final realizez un layout, pun toate piesele in el si il atasez grupului
- returnez adresa grupului.

 Daca ar fi singur, al patrulea grup, pozitia D, ar arata asa:

Cu toate cele patru groupbox-uri, fereastra arata ca in imagine:


 Sfarsit pentru azi.

-----------------------------------------------------------------------------------------------------------------
Nota: Explicatiile proprietatii flat suna asa in documentatie. In practica, pe Linux, la stilul curent, nu am vazut deosebiri.
flat : bool
This property holds whether the group box is painted flat or has a frame
A group box usually consists of a surrounding frame with a title at the top. If this property is enabled, only the top part of the frame is drawn in most styles; otherwise, the whole frame is drawn.
By default, this property is disabled, i.e., group boxes are not flat unless explicitly specified.
Note: In some styles, flat and non-flat group boxes have similar representations and may not be as distinguishable as they are in other styles.


-------------------------------------------------------------------------------------------------------------------
Codul de mai sus fiind sub o anumita licenta, sunt obligat sa includ fisierul cu licenta:

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

Niciun comentariu:

Trimiteți un comentariu