Er det en ting jeg aldri har gjort så er det å lage et grafisk grensesnitt til et program i Linux. Har stort sett bare laget web-skript/applikasjoner eller terminal-applikasjoner. Så da tenkte jeg at jeg skulle utforske dette. Et grensesnitt som skal være godt utarbeidet er Qt

Har vært borti det for mange, mange år siden men husker i grunnen ingenting av det, så jeg tenkte at jeg skulle hive meg på dette. Vel og merke C++ versjonen. Lenge siden jeg har sett eller programmert i C++ så det kan jo være interessant nok det. Så hva slags verktøy er det jeg bruker?

  1. Qt Designer
  2. kdevelop

Qt Designer er veldig enkelt å forstå. Man starter med å velge hva lags type du vil ha: Dialog, MainWindow, eller Widget. Hva forskjellen er jeg jammen meg ikke sikker på bortsett fra at Dialog-bokser er jo ganske forståelig å skjønne hva er. Men jeg velger å starte med en widget. Legger på de komponentene jeg vil ha og...TADA! så har vi et vindu som ser ut som bildet nedenfor. For å få sagt det: Jeg har lagt til komponentene i bildet fordi jeg skal prøve ut ting. Hva er det jeg skal prøve ut? Skal prøve ut hvordan man få ting til å skje når man trykker på knapper eller når man gjør en handling i vinduet. Hvis jeg ikke husker feil så brukte windows (en gang i tiden) callback-funksjoner for å gjøre ting. Qt bruker "signals and slots". Dvs man sender et signal fra fra a til en slot i b...ja ja...slik ser iallefall widget'en min ut:

Veldig enkelt:

  • venstre redigeringslinje
  • høyre redigeringslinje
  • knapp i mellom som skal sende tekst fra den ene til den andre
  • kryssboks for å velge om man skal sende til høyre eller venstre
  • avsluttnings-knapp
  • tøm innholds knapp(tilbake til default)

I Qt har man ferdige funksjoner for å beskrive en handling. Dvs fra hvilket objekt og hvilket objekt den skal påvirke. Man går på "Edit" i menyen og velger "Edit Signals/Slots". Her drar man en linje mellom objektene for å fortelle hva som skal skje når en handling blir gjort. Se bildet nedenfor:

Avslutt-knappen har en funksjon: Å lukke applikasjonen. Da lager man en linje fra knappen og til hoved-vinduet. Det vil da dukke opp en rekke valg: Hva slags signal som skal utløses på knappen, og hva som skal skje med hovedvinduet når dette skjer. I dette tilfellet: clicked( ) og close( ). Det samme gjør man med de andre, og man får et bilde som ovenpå. Men hva om det ikke finnes en funksjon for hva som skal skje?

Når vi klikker på knappen "Send Tekst", så skal man sende tekst fra venstre-felt til høyre-felt. En veldig enkel operasjon skulle man tro. Jeg syntes ikke det var enkelt. Men jeg fant en metode til slutt som fungerte som hodet mitt forstod iallefall. I første omgang så kunne jeg ikke forstå hvorfor jeg fikk visse feilmeldinger men jeg fant ut en løsning på det, og det er det jeg skal vise lenger ned.

En annen ting som jeg ikek har funnet ut av er hvordan jeg skal kunne importere ui-fila til kdev, eller hvordan jeg skal lagre widgeten som en "pro"-fil for å kunne importere den i kdev, så jeg gjorde det på den "vanskelige" metoden. Gå inn i menyen og trykk på "Form"->"View Code". Da får man fram klassen kildekoden i form av en headerfil(for C++). Før man gjør noe mer så må man lage et qt-prosjekt i kdevelop som nedenfor:

Denne malen lager en enkel applikasjon/Klasse som ikke inneholder noe bortsett fra noe kode i konstruktøren. Denne koden fjerner man. Det er bare tullball og viss-vass da vi skal "importere" klassen fra Qt-Designer. Koden fra Designer ser slik ut:

/********************************************************************************
** Form generated from reading UI file 'test3O20894.ui'
**
** Created
**      by: Qt User Interface Compiler version 4.8.4
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef TEST3O20894_H
#define TEST3O20894_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QCheckBox>
#include <QtGui/QHeaderView>
#include <QtGui/QLineEdit>
#include <QtGui/QPushButton>
#include <QtGui/QWidget>

QT_BEGIN_NAMESPACE

class Ui_qobjTest3
{
public:
    QPushButton *pbAvslutt;
    QPushButton *pbTomInnhold;
    QPushButton *pbSendTekst;
    QLineEdit *leHoeyre;
    QLineEdit *leVenstre;
    QCheckBox *cbHellerV;

    void setupUi(QWidget *qobjTest3)
    {
        if (qobjTest3->objectName().isEmpty())
            qobjTest3->setObjectName(QString::fromUtf8("qobjTest3"));
        qobjTest3->resize(693, 262);
        pbAvslutt = new QPushButton(qobjTest3);
        pbAvslutt->setObjectName(QString::fromUtf8("pbAvslutt"));
        pbAvslutt->setGeometry(QRect(450, 220, 99, 23));
        pbTomInnhold = new QPushButton(qobjTest3);
        pbTomInnhold->setObjectName(QString::fromUtf8("pbTomInnhold"));
        pbTomInnhold->setGeometry(QRect(570, 220, 99, 23));
        pbSendTekst = new QPushButton(qobjTest3);
        pbSendTekst->setObjectName(QString::fromUtf8("pbSendTekst"));
        pbSendTekst->setGeometry(QRect(290, 80, 99, 23));
        leHoeyre = new QLineEdit(qobjTest3);
        leHoeyre->setObjectName(QString::fromUtf8("leHoeyre"));
        leHoeyre->setGeometry(QRect(400, 80, 113, 22));
        leVenstre = new QLineEdit(qobjTest3);
        leVenstre->setObjectName(QString::fromUtf8("leVenstre"));
        leVenstre->setGeometry(QRect(160, 80, 113, 22));
        cbHellerV = new QCheckBox(qobjTest3);
        cbHellerV->setObjectName(QString::fromUtf8("cbHellerV"));
        cbHellerV->setGeometry(QRect(290, 110, 111, 21));

        retranslateUi(qobjTest3);
        QObject::connect(pbAvslutt, SIGNAL(clicked()), qobjTest3, SLOT(close()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked()), leVenstre, SLOT(clear()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked()), leHoeyre, SLOT(clear()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked(bool)), cbHellerV, SLOT(setChecked(bool)));

        QMetaObject::connectSlotsByName(qobjTest3);
    } // setupUi

    void retranslateUi(QWidget *qobjTest3)
    {
        qobjTest3->setWindowTitle(QApplication::translate("qobjTest3", "TestObjects", 0, QApplication::UnicodeUTF8));
        pbAvslutt->setText(QApplication::translate("qobjTest3", "Avslutt", 0, QApplication::UnicodeUTF8));
        pbTomInnhold->setText(QApplication::translate("qobjTest3", "T\303\270m Innhold", 0, QApplication::UnicodeUTF8));
        pbSendTekst->setText(QApplication::translate("qobjTest3", "Send Tekst", 0, QApplication::UnicodeUTF8));
        cbHellerV->setText(QApplication::translate("qobjTest3", "Mot Venstre", 0, QApplication::UnicodeUTF8));
    } // retranslateUi

};

namespace Ui {
    class qobjTest3: public Ui_qobjTest3 {};
} // namespace Ui

QT_END_NAMESPACE

#endif // TEST3O20894_H

Det som er viktig i denne klasse er det som er satt som "public". Objektene(knapper, redigeringslinjer osv...), og de to funksjonene setupUi(..), retranslateUi(...). Dette er bare initialiseringsfunksjoner som inneholder posisjon og annet dill-dall(egenskaper), som du har satt i Qt-designer. For å rydde litt kan man selvfølgelig fjerne dette fra header-fila og skrive det inn i cpp-fila. Men det gidder vi ikke nå. Alt annet trenger man ikke, bortsett fra kallet til header-filene på toppen. Iallefall...når disse tingene er kopiert så vil man ha en ren og fin header fil som er lett å forstå. Det er en ting man må gjøre først: Gå inn i konstruktøren og kall på setupUi(...). Det er alt man trenger å gjøre. Da er prosjektet "importert". Egentlig fryktelig tungvindt, men når jeg ikke har funnet ut noe bedre så kan det bare slik. Foreløpig. Nå!...Tilbake til "signals and slots":

Jeg skal lage et signal når knappen "Send tekst" bilr klikket på. Først må vi lage en funksjon som skal bli kalt på. Dette gjør vi slik:

class test3designer : public QMainWindow
{
Q_OBJECT

public slots:
  void send_text(void);

I setupUi-funksjonen bruker jeg funksjonen connect som skal kople handlingen "cliked" til funksjonen. Som nedenfor:

connect(this->pbSendTekst, SIGNAL(clicked()), SLOT(send_text()));

Det som jeg syntes er litt merkelig er at jeg må bruke connect med 3 parametere og ikke 4. Den med 4 parametere ser slik ut i praksis:

QObject::connect(pbAvslutt, SIGNAL(clicked()), qobjTest3, SLOT(close()));

Som er ganske forståelig. Men det er rom for å forstå mer har jeg skjønt, men jeg har iallefall funnet en metode som fungerer. Iallefall. Hele klassen etter at ting ble kopiert og noe ekstra funksojner ble skrevet , blir seendes slik ut:

class test3designer : public QMainWindow
{
Q_OBJECT

public slots:
  void send_text(void);
  void skift_text(void);
public:
    QPushButton *pbAvslutt;
    QPushButton *pbTomInnhold;
    QPushButton *pbSendTekst;
    QLineEdit *leHoeyre;
    QLineEdit *leVenstre;
    QCheckBox *cbHellerV;
    void setupUi(QWidget *qobjTest3)
    {
        if (qobjTest3->objectName().isEmpty())
            qobjTest3->setObjectName(QString::fromUtf8("qobjTest3"));
        qobjTest3->resize(693, 262);
        pbAvslutt = new QPushButton(qobjTest3);
        pbAvslutt->setObjectName(QString::fromUtf8("pbAvslutt"));
        pbAvslutt->setGeometry(QRect(450, 220, 99, 23));
        pbTomInnhold = new QPushButton(qobjTest3);
        pbTomInnhold->setObjectName(QString::fromUtf8("pbTomInnhold"));
        pbTomInnhold->setGeometry(QRect(570, 220, 99, 23));
        pbSendTekst = new QPushButton(qobjTest3);
        pbSendTekst->setObjectName(QString::fromUtf8("pbSendTekst"));
        pbSendTekst->setGeometry(QRect(290, 80, 99, 23));
        leHoeyre = new QLineEdit(qobjTest3);
        leHoeyre->setObjectName(QString::fromUtf8("leHoeyre"));
        leHoeyre->setGeometry(QRect(400, 80, 113, 22));
        leVenstre = new QLineEdit(qobjTest3);
        leVenstre->setObjectName(QString::fromUtf8("leVenstre"));
        leVenstre->setGeometry(QRect(160, 80, 113, 22));
        cbHellerV = new QCheckBox(qobjTest3);
        cbHellerV->setObjectName(QString::fromUtf8("cbHellerV"));
        cbHellerV->setGeometry(QRect(290, 110, 111, 21));

        retranslateUi(qobjTest3);
	
        QObject::connect(pbAvslutt, SIGNAL(clicked()), qobjTest3, SLOT(close()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked()), leVenstre, SLOT(clear()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked()), leHoeyre, SLOT(clear()));
        QObject::connect(pbTomInnhold, SIGNAL(clicked(bool)), cbHellerV, SLOT(setChecked(bool)));
	QMetaObject::connectSlotsByName(qobjTest3);
	connect(this->pbSendTekst, SIGNAL(clicked()), SLOT(send_text()));
	connect(this->cbHellerV, SIGNAL(toggled(bool)), SLOT(skift_text()));
    } // setupUi

    void retranslateUi(QWidget *qobjTest3)
    {
        qobjTest3->setWindowTitle(QApplication::translate("qobjTest3", "TestObjects", 0, QApplication::UnicodeUTF8));
        pbAvslutt->setText(QApplication::translate("qobjTest3", "Avslutt", 0, QApplication::UnicodeUTF8));
        pbTomInnhold->setText(QApplication::translate("qobjTest3", "Tøm Innhold", 0, QApplication::UnicodeUTF8));
        pbSendTekst->setText(QApplication::translate("qobjTest3", "Send Tekst", 0, QApplication::UnicodeUTF8));
        cbHellerV->setText(QApplication::translate("qobjTest3", "Mot Høyre", 0, QApplication::UnicodeUTF8));
    } // retranslateUi
    test3designer()
    {
      setupUi(this);
    };
    virtual ~test3designer()
    {
      delete pbAvslutt;
      delete pbTomInnhold;
      delete pbSendTekst;
      delete leHoeyre;
      delete leVenstre;
      delete cbHellerV;
    }
};

Funksjonen send_tekst er veldig enkel. Den bare skrifter tekst i de forskjellige boksene alt ettersom. Slik ser den ut:

void test3designer::send_text(void )
{
  bool bcheckBox = cbHellerV->isChecked();
  if(bcheckBox)
    this->leVenstre->setText(this->leHoeyre->text());
  else
    this->leHoeyre->setText(this->leVenstre->text());
}

Når alt dette sitter så er det veldig moro faktisk. Veldig enkelt å bruke "Qt Designer", selv om jeg skulle gjerne ha funnet en enklere måte å eksportere/importere prosjektet på.