Q_INVOKABLE oder wie kann ich Qt Funktionen in Qml benutzen?

Wir möchten in unserem Beispiel die Qt Funktion currentDateTime() in unserem Qml File benutzen um die aktuelle Zeit anzuzeigen.

Dazu fügen wir in unser myclass.h File die Beschreibung Q_INVOKABLE ein, was soviel heist wie die Funktion in Qml aufrufbar machen.

class MyClass : public QObject
{
    Q_OBJECT 
public:
    MyClass();
    ~MyClass();

    Q_INVOKABLE QDateTime getCurrentDateTime() //<--- unser Name für die in qml Aufrufbare Funktion 
     const {
        return  QDateTime::currentDateTime(); //Eigentliche Qt-Funktion
     }

signals:
    void setlabeltext(QString text);
public slots:
    void cppSlot(QString msg);
};

Jetzt müssen wir nur noch die Funktion irgendwie in unserem Qml file Aufrufen,

doch zuerst fügen wir in unser main.qml main_window über den Designer ein Rechteck und ein neues Label für Datum und Uhrzeit ein.

datum_uhrzeit

Diesen Label Text wollen wir nun jede Sekunde aktualisieren dazu verwenden wir die Vorher gelernte Möglichkeit C++ Signale mit Qml zu verbinden. (Den TextNamen text1 ändern wir noch auf datumzeit.)
Anschließend erstellen wir uns einen Timer und ein Signal sowie einen Slot in unserer myclass.h

#include <QObject>
#include <QDateTime>
#include <QDebug>
#include <QTimer>

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass();
    ~MyClass();
    QTimer * SecondsTimer;
    Q_INVOKABLE QDateTime getCurrentDateTime()
     const {
        return  QDateTime::currentDateTime();
     }
signals:
    void setlabeltext(QString text);
    void emit_timer_second();

public slots:
    void cppSlot(QString msg);
    void emit_timer();
};

Unsere main.cpp erweitern wir um den Slot emit_timer() und füllen den Konstruktor MyClass mit etwas Leben das einen Timer erzeugt,verbindet und startet.

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "myclass.h"
#include <QQmlContext>
#include <QDateTime>
#include <QtCore>
#include <QDebug>
#include <QQuickItem>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QtQuick2ApplicationViewer viewer;

    MyClass data;
    viewer.rootContext()->setContextProperty("myclassData", &data);
    viewer.setMainQmlFile(QStringLiteral("qml/qtquick_uebung/main.qml"));

    //Verbindung von C++ über Signal Slots nach QML
    QString msg = "Dieser Text kommt von c++";
    emit data.setlabeltext(msg);

    //Verbindung von QML über Signal Slots nach C++
    QObject* viewerobject = viewer.rootObject();
    QObject::connect(viewerobject,SIGNAL(qmlSignal(QString)),&data,SLOT(cppSlot(QString)));

    MyClass(); //<-- hier wird myclass Aufgerufen
    viewer.showExpanded();
    return app.exec();
}

MyClass::MyClass()
{
    SecondsTimer = new QTimer(this);
    QObject::connect(SecondsTimer,SIGNAL(timeout()),this,SLOT(emit_timer()));
    SecondsTimer->start(1000);
}

MyClass::~MyClass()
{ 
}

void MyClass::cppSlot(QString msg)
{
  qDebug() << QString("Called the C++ slot with message:%1").arg(msg);
}

void MyClass::emit_timer()
{
    emit emit_timer_second();
}

Der Slot emit_timer() wird nun jede Sekunde aufgerufen und emittiert das Signal emit_timer_second(), dieses Signal fangen wir nun noch in Qml auf und setzen unsere Q_INVOKABLE Funktion ein um das DatumZeit Label auf die aktuelle Systemzeit zu setzen. Das Target für unser Signal ist immer noch myclassData daher fügen wir nun auch diesen Slot in Connections ein (Großbuchstabe beachten)

  Connections {
                   target: myclassData
                   onSetlabeltext: {
                     labeltext.text=text
                   }

                   onEmit_timer_second: {
                     datumzeit.text=Qt.formatDateTime(myclassData.getCurrentDateTime(),"dd.MM.yyyy:hh.mm.ss") //<--datumzeit ist unser neues label das wir nun setzen 
                   }
}

  Rectangle {           //die neuen Elemente Hellgruenes Rechteck und Text datumzeit
        id: rectangle1
        x: 0
        y: 0
        width: 360
        height: 27
        color: "#4dc635"

        Text {
            id: datumzeit
            x: 0
            y: 0
            width: 360
            height: 27
            text: Qt.formatDateTime(myclassData.getCurrentDateTime(),"dd.MM.yyyy:hh.mm.ss") //wenn wir von anfang an die aktuelle Zeit sehen wollen müssen wir den Text vorher setzen
            horizontalAlignment: Text.AlignRight
            font.pixelSize: 21
        }
    }

und voila wir bekommen das aktuelle Datum und aktuelle Zeit in unserem Label angezeigt

q_invokable

States und Transitions

Nun wollen wir etwas Bewegung in unser Programm bringen dazu verwenden wir die Möglichkeit von Qt Quick States zu erstellen.

Ein State ist ein Zustand bei dem sich Irgend ein vorhandenes Objekt verändert z.B in seiner Größe , Position oder sonstigen Eigenschaften.

Um einen State zu erstellen  gehen wir in den Designer und klicken oben auf das Plus wir erstellen für unser Beispiel 2 zusätzliche States in denen wir unseren Button an eine andere Position setzen.

states

Wir können beliebig viele States erstellen.  Im qml-Code wird eine Liste erstellt die die Einzelnen States und ihre Veränderung anzeigt.

    states: [
        State {
            name: "State1"

            PropertyChanges {
                target: button1
                x: 0
                y: 260
            }
        },
        State {
            name: "State2"
            PropertyChanges {
                target: button1
                x: 260
                y: 260
            }
        }
    ]

Eine Liste ist immer durch die [ ] gekennzeichnet.

So jetzt müssen wir nur noch den Zustand Irgendwie ändern aber wie ?

Wir wollen das bei jedem klick auf den Button in den nächsten Zustand gewechselt wird. Dazu müssen wir eine Variable Index einführen

Variablen heissen in qml property. Diese fügen wir in die geschweiften Klammern von Rectangle zu Beginn ein.

 property int index: 0

Diese Property können wir nun bei jedem klick erhöhen und sie als Indentifikator für unseren Zustand verwenden dazu fügen wir folgenden Code in die onClicked: Eigenschaft des Buttons.

  onClicked:{
                    index++
                    labeltext.text=index

                    if (index>=3)index=0;
                    if (index==0)main_window.state=""
                    if (index==1)main_window.state="State1"
                    if (index==2)main_window.state="State2"

              }

Der Grundzustand wird wieder erreicht durch die „“ was keinem Zustand also dem Normal Zustand entspricht. main_window ist die id unseres Rectangles die wir noch vergeben müssen da wir bis dato keine id dafür haben. Dort wo Hallo World steht wird der aktuelle Index angezeigt. Starten wir nun das Programm können wir die Zustände durch klicken auf unseren Knopf durchschreiten.

Ein bisschen lahm sieht das ganze schon aus daher fügen wir eine Animation hinzu,die in qml Transition genannt wird.

 transitions: Transition {
           NumberAnimation { properties: "x,y"; easing.type: Easing.InBounce }
       }

Hier eine NumberAnimation der x,y Koordinaten unseres Buttons, der easing.type gibt die Bewegung an. Klicken wir mit rechter Maustaste auf das easing.type argument können wir mit Qt Quick Werkzeugleiste anzeigen die gewünschte Bewegungsanimation einstellen. (Dies ist immer möglich wenn eine kleine Glühbirne im Editor erscheint diese erscheint wenn wir z.b unseren Cursor hinter die Number Animation setzen )

qt_quick_tool

Mit der Werkzeugleiste können wir uns die Animation durch klicken auf den Play Pfeil anschauen  und beliebig verändern.

Nun haben wir eine erste Anwendung mit Bewegung hier nochmal der komplette Code wie er bissher bei mir aussieht:

import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0

Rectangle {
    id: main_window
    property int index: 0
    width: 360
    height: 360
    color: "#1e864b"
    radius: 0
    transformOrigin: Item.Center
    Text {
        id: labeltext
        text: qsTr("Hello World")
        opacity: 1
        smooth: true
        anchors.centerIn: parent
    }
    MouseArea {
        id: mousearea1
        x: 0
        y: 0
        anchors.rightMargin: 0
        anchors.bottomMargin: 0
        anchors.leftMargin: 0
        anchors.topMargin: 0
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }

                Button {
                    id: button1
                    x: 130
                    y: 40
                    width: 100
                    height: 100

                    style: ButtonStyle {
                            background: Rectangle {
                                implicitWidth: 100
                                implicitHeight:100
                                border.width: control.activeFocus ? 2 : 1
                                border.color: "green"

                                radius: width/2
                                gradient: Gradient {
                                    GradientStop { position: 0 ; color: control.pressed ? "lightgreen" : "blue" }
                                    GradientStop { position: 1 ; color: control.pressed ? "darkgreen" : "darkblue" }
                                }
                            }
                        }

                    text: "Button"
                    tooltip: "Das ist ein Button"

                    onClicked:{
                                index++
                                labeltext.text=index

                                if (index>=3)index=0;
                                if (index==0)main_window.state=""
                                if (index==1)main_window.state="State1"
                                if (index==2)main_window.state="State2"

                              }

                     //hier wird der Text beim clicken geändert
                }

    }
    states: [
        State {
            name: "State1"

            PropertyChanges {
                target: button1
                x: 0
                y: 260
            }
        },
        State {
            name: "State2"
            PropertyChanges {
                target: button1
                x: 260
                y: 260
            }

        }
    ]

    transitions: Transition {
           NumberAnimation { properties: "x,y"; easing.type: Easing.InBounce }
       }

}

Custom Styles für Qt Quick Controls

Hmm ich möchte meinem Knopf eine andere Farbe und Form geben aber es gibt im QtQD keine Farbauswahl für mein Button Objekt.  Also wie stelle ich das an?

Die Lösung heist:

import QtQuick.Controls.Styles 1.0

hiermit lässt sich der Style in unserem fall der Buttonstyle anpassen.

Dazu müssen wir bei unserem Button folgenden Code einfügen:

 Button {
          id: button1
          x: 130
          y: 38
          width: 100
          height: 100
          style: ButtonStyle 
                {
                 background: Rectangle 
                      {
                        color: control.pressed ? "green" : "blue"  //ist der Knopf gedrückt wenn nein blau wenn ja grün
                        implicitWidth: 100                         //wird keine Größe angegeben werden die impliciten größen verwendet 
                        implicitHeight:100
                        border.width: control.activeFocus ? 2 : 1 //wird mit tab auf activer focus geschaltet verändert sich der Button Rand
                        border.color: "#999"
                        radius: width/2 // die Größe halbiert ergibt einen Runden Button
                      }
                 }
          }

Der Ternary Operator bedeutet folgendes: condition ? true-statement : false-statement

qml_button_style

Schon haben wir einen bunten Knopf der grün wird wenn wir ihn drücken.
Ein bisschen hässlich sieht er ja schon aus unser Knopf um ihn zu verschönern belegen wir ihn mit einem Gradienten

also in die geschweifte Klammer von Style->Rectangle  folgendes einfügen:

  gradient: Gradient {
                        GradientStop { position: 0 ; color: control.pressed ? "lightgreen" : "blue" }
                        GradientStop { position: 1 ; color: control.pressed ? "darkgreen" : "darkblue" }
                     }

Es wird ein Farbübergang von position 0 auf position 1 gemacht (man kann beliebig viele Positionen einfügen) in unserem Fall wenn der Knopf nicht gedrückt ist von blue->darkblue und wenn er gedrückt ist von lightgreen nach darkgreen hier kann man auch jede Beliebige Farbe wählen von #fffff bis #00000. Der Gradient überschreibt die eigenschaft color daher can die Zeile color: control.pressed ? „green“ : „blue“ gelöscht werden

qml_button_style_2

Jetzt schaut unser Knopf schon ansehnlicher aus das Problem  im QtQD wird der Runde Button manchmal nicht sofort angezeigt dort sieht man nach wie vor einen Eckigen Button mit den Standard styles.

Nach einem Neustart vom QtCreator sieht man aber auch hier den runden Entwurf.

Qt Quick Controls unser erster Button

Hallo wir wollen nun einen Button einfügen der z.b unseren Hallo Welt text beim clicken ändert.

Dazu importieren wir in unserem main.qml

import QtQuick.Controls 1.0

Gehen wir dann in unseren QtQD erhalten wir weitere Optionen in unserer QML-Typen auswahl Es gibt diverse controls die wir schon aus der Widget Programmiereung her kennen.

Buttons,Checkboxen Slider…. etc. Wir wählen nun einen Button aus und ziehen ihn auf unser Rectangle.

qml_designer_controls

Diesen Button Können wir Rechts unter Button zusätzlich bearbeiten zb können wir ihn noch mit einem Tooltip versehen oder ein Bild für den Button auswählen.

Starten wir das Programm sehen wir den Button wie gewünsch jedoch wenn wir draufklicken geschieht nichts?

Da wir unseren Hallo Welt Text ändern wollen verpassen wir ihm eine id: damit lässt er sich direkt im qml code ansprechen. Daher ist es wichtig die id’s immer sorgfältig zu wählen damit man später genau weis was sich darunter verbirgt.

Das Label anklicken und oben rechts die ID eintragen:

qml_designer_id

Wir nennen unseren „Hallo Welt“ Text labeltext.

Wir können auch alternativ im Code in die Geschweiften Klammern von Text die id händisch einfügen:

 Text {
        id: labeltext
        text: qsTr("Hello World")
        opacity: 1
        smooth: true
        anchors.centerIn: parent
    }

So jetzt verbinden wir noch den Button mit der Aktion Text ändern mit einem onClicked: 

der ganze Code sieht dann wie folgt aus:

import QtQuick 2.0
import QtQuick.Controls 1.0

Rectangle {
    width: 360
    height: 360
    color: "#1e864b"
    radius: 0
    transformOrigin: Item.Center
    Text {
        id: labeltext
        text: qsTr("Hello World")
        opacity: 1
        smooth: true
        anchors.centerIn: parent
    }
    MouseArea {
        x: 0
        y: 0
        anchors.rightMargin: 0
        anchors.bottomMargin: 0
        anchors.leftMargin: 0
        anchors.topMargin: 0
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }

        Button {
            id: button1
            x: 143
            y: 68
            text: "Button"
            opacity: 1
            scale: 1
            rotation: 0
            onClicked:{labeltext.text="Button Clicked"} //hier wird der Text beim clicken geändert
        }
    }
}

Starten wir nun das Programm wird das label beim drücken des Knopfes geändert.
bei erneutem drücken geschieht jedoch nichts mehr wir können die onClicked: eigenschaft mit einem if statement erweitern so z.B  :

 onClicked:{
                        if (labeltext.text=="Button Clicked")
                        {
                            labeltext.text="Hello World"
                        }
                        else
                        {
                            labeltext.text="Button Clicked"
                        }
                      }

Nun ändert sich der Text bei jedem click.

qml_button_clicked

Möchte man den Button direkt mit C++ Code Verknüpfen ist das etwas komplizierter.

Wir wollen zuerst die Spezialitäten von qml beleuchten und zur Verknüpfung mit C++-Code kommen wir später…

Sprache zur Laufzeit ändern

Nun möchten wir unser Program auch in verschiedenen Ländern verteilen dazu soll der Anwender seine Landes Sprache selbst auswählen können.

Hierbei hilft uns das programm kürzel tr() und der Qt Linguist.

Jeder QString der in ein tr eingefasst ist wird später mit dem Linguisten extrahiert so das man eine Übersetzung dafür eingeben kann, die dann über einen QTranslator im Programm eingefügt wird, doch dazu später mehr.

Die von uns erstellten Formulare form.ui und mainwindow.ui wurden automatisch mit dem tr Kürzel versehen man muss nur sicherstellen das man die funktion retranslateUi() aufruft.

schaut man sich die generierten files ui_mainwindow.h oder ui_form.h an sieht man in der Funktion retranslateUi(QMainwindow *Mainwindow) z.B folgendes

actionLaden->setText(QApplication::translate("MainWindow", "laden", 0, QApplication::UnicodeUTF8));

Was im Prinzip einem tr(„laden“) kürzel entspricht der Menüpunkt laden befindet sich Irgendwo in unserem Menübar.

Bei allen Texten die man selbst in den Code einfügt muss man jedoch auch selbst dafür sorge tragen, dass sie später vom Linguisten erkannt werden.

In unserem Beispiel gibt es Momentan leider keinen solchen Text, daher fügen  wir als Beispiel ein Label in unser mainwindow.ui ein.

neues label

Wir fügen dann noch in unseren TimerEvent  ein ui->label_2->setText() ein.

void MainWindow::timerEvent(QTimerEvent *event)
{
  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString(Qt::LocalDate);
  ui->label->setText(stime);
  ui->label_2->setText(tr("das ist ein zu\nübersetzender Text"));<--- hier ist nun unser tr()
}

Macht zwar hier keinen richtigen Sinn verdeutlicht aber sehr gut die Funktionsweise des Translators. Denn jedesmal wenn der Text gesetzt wird, hier also jede Sekunde  wird er auch erst übersetzt. Bzw der übersetzte Text, von dem aktuell Installierten QTranslator, eingefügt. Im späteren Programmablauf sieht man diesen Text dann wie er sich nach einer Sekunde aktualisiert, zwischendrin sieht man den „Standard Text“ aus dem .ui File.

Anschließend benötigen wir noch eine Möglichkeit die Sprache einzustellen dafür verwende ich nun eine ComboBox:

combobox

hier kann man nun mit einem Doppelklick und das grüne Plus die gewünschten Sprachen eintragen zunächt einmal deutsch und english.

Wichtig ist unter Eigenschaften diese Texte nicht für die Übersetzung zu markieren. Da wir sie später verwenden wollen, um zu entscheiden welche Sprachdatei wir auswählen. Also nicht Übersetzen sonst führt das zur kompletten Verwirrung.

Jetzt benötigen wir noch einen QTranslator  dazu fügen wir in unsere mainwindow.h einen QTranslator ein und einen neuen Slot change_language

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_form.h"
#include <QMainWindow>
#include <QTranslator> <------ hier die Klasse Qtranslator includen
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QDialog *newform;
    Ui::Form Form;
    QString numbOne;
    QTranslator language_en; <------ hier eine Variable vom typ QTranslator anlegen.
protected:
    void timerEvent(QTimerEvent *event);
private slots:
    void on_actionSlider_triggered();
    void on_actionLaden_triggered();
    void on_actionSpeichern_triggered();
    void on_actionQt_Info_triggered();
void resetall();
void change_language(QString language); <--- unser neuer Slot change_language
};
#endif // MAINWINDOW_H

Diesen Slot fügen wir nun auch noch in unser mainwindow.cpp ein:

void MainWindow::change_language(QString language)
{
if (language=="deutsch")
{
    qApp->removeTranslator(&language_en); //die Ursprungssprache wird hergestellt
}
if (language=="english")
{
    language_en.load("Egal_en"); <--- Aufruf der .qm Datei wenn sich die Datei direkt im Buildpfad befindet
    qApp->installTranslator(&language_en); //die Englishe Translationsdatei wird geladen 
}
}

Zusätzlich benötigen wir noch einen connect der combobox auf unseren neuen Slot im Konstruktor MainWindow::MainWindow:

connect(ui->comboBox,SIGNAL(currentIndexChanged(QString)),this,SLOT (change_language(QString)));

So nun haben wir unser Programm schonmal vorbereitet auf eine Übersetzung nun benötigen wir nur noch die Übersetzte Textdatei dazu fügen wir in unser Egal.pro folgenden Eintrag hinzu:

TRANSLATIONS += Egal_en.ts

dieser Eintrag wird benötigt um eine Text-Datei für den Qt Linguist zu erzeugen. Nochmal neu Kompilieren nicht vergessen!

Anschließend gehen wir auf  Extras->Extern->Linguist->Übersetzungen aktualisieren und führen damit ein lupdate aus. Nun sollte ein Egal_en.ts file in unserem Projectordner erstellt worden sein. Diese öffnen wir nun mit dem Qt Linguist  (bei mir zu finden unter D:\tools\Qt\bin\linguist.exe)

linguist

Hier sehen wir nun unser Mainwindow.ui und Form.ui wieder es werden alle gefundenen Texte die zum übersetzen markiert wurden angezeigt.

Jetzt gehts ans übersetzen Englisch krieg ich grade noch freihand hin… 🙂 Also überall eine Übersetzung eintragen. Man kann die bereits Übersetzen Texte mit einem grünen Häckchen markieren, Texte die nicht Übersetzt werden sollen, einfach nix eintragen. Wenn wir fertig sind das Egal_en.ts file speichern.

Nun füren wir ein lrelease aus indem wir im Creator über Extras-> Extern->Linguist->Übersetzung freigeben gehen.

Es wird ein Egal_en.qm file erzeugt das einer Binärdatei entspricht die im Code eingebunden wird.  Diese müssen wir in das jeweilige Build Verzeichniss kopieren (Hier D:\Qt_uebung\Egal-build-desktop-Qt_4_8_1_for_Desktop_-_MSVC2008__Qt_SDK__Debug wenn wir uns im Debug befinden. Oder die bessere Alternative wir packen sie in eine Resourcendatei. Dazu erstellen wir mit Rechtsklick auf unser Project Egal.pro->Hinzufügen->Qt->Qt Resourcedatei, dann muss man noch einen Namen für die Resourcedatei eingeben z.B. sprachen.qrc. Haben wir die Datei erstellt wählen wir sie im Project Explorer mit Doppelklick aus und gehen auch hier auf hinzufügen den prefix setzen wir auf „/“ da wir kein Unterverzeichnis haben in dem sich unsere Sprachdatei befindet. Nochmals Hinzufügen->Datei hinzufügen und die Egal_en.qm Datei auswählen.

sprache resource

Jetzt muss man noch darauf achten das man den Pfad im Aufruf im Programm wenn man eine Resourcendatei verwendet auf :

language_en.load(":/Egal_en");<--- Aufruf der .qm Datei wenn sich die Datei in einer Resourcendatei befindet

ändern muss damit unsere .qm Datei auch gefunden wird.

Jetzt müssen wir nur noch dafür sorgen das nachdem wir die Neue Sprache eingestellt haben auch ein retranslateUi ausgeführt wird.

dazu erstellen wir einen Event Handler  changeEvent(QEvent *event) der Überprüft ob die Sprachdatei per removeTranslator oder installTranslator geändert wurde.

im mainwindow.h fügen wir unter protected: (ähnlich dem timerevent) unser changeEvent ein:

protected:
    void timerEvent(QTimerEvent *event);
    void changeEvent(QEvent *e); <---- Ein neuer Event Handler

In Mainwindow.cpp fügen wir nun ein:

void MainWindow::changeEvent(QEvent *e)
{
    switch (e->type()) 
    {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

Um das eingehende changeEvent zu unterscheiden, wir wollen momentan nur auf ein LanguageChange Event reagieren.

Starten wir jetzt das Programm und wechseln die Sprache auf english werden alle zur Übersetzung markierten Texte, für die eine Übersetzung im .ts file existiert,  ersetzt.

translated gui

Versuchen sie als Übung weitere Sprachen einzubauen. Man sollte hier darauf achten das man bei mehreren Sprachen besser eine eigene Sprachdatei für „deutsch“ erstellt und somit den removeTranslator durch einen installTranslator(deutscheSprache) ersetzt. Oder man muss sich merken welcher Translator gerade installiert ist um auch den richtigen wieder zu removen.

standalone Anwendung generieren

Folgendes Problem stellt sich ein wenn man seine selbst geschriebene Software an einen Kollegen weiterleiten möchte, dieser aber kein Qt Installiert hat. Der Kollege bekommt die Fehlermeldung:

fehlermeldung_gt4gui

QtGui4.dll konnte nicht gefunden werden?

Hm was nun ?

Eine Standalone Version des Programms muss her! Nach dem lesen dieses Artikels wurde klar eine statisch gelinkte QT Version muss her.

Daher habe ich mir nochmals die Qt Bibliotheken hier heruntergeladen. (siehe da mittlerweile gibt es sogar schon Version 4.8.4).

In meinem Fall hab ich also die Qt Libraries 4.8.4 for Windows (VS 2008) heruntergeladen ,da ich ja den MSVC2008 Compiler verwende, und in ein eigenes Verzeichniss installiert (bei mir D:\tools\Qt_4_8_4 )

Danach muss man die Console von Visual Studio öffnen (Einfach nach „Visual Studio 2008 Eingabeaufforderung“ suchen)

dann in das verzeichniss D:\tools\Qt_4_8_4 wechseln und configure mit folgenden kommandos ausführen :

configure -release -static -platform win32-msvc2008

configure

Nun wird man nach dem verwendeten lizenz Modell gefragt wir benutzen opensource ‚o‘, anschließend läuft die configuration durch das dauert dann einige Minuten.

Ist die Konfiguration abgeschlossen kommt erst der lange Teil das statische neu kompilieren der Qt Bibliotheken dauert nämlich ca. 2 Std.

geben sie nun noch:

nmake

ein. Anschließend können sie zuschauen wie die Files neu kompiliert werden oder in der Nase popeln.

(2 Stunden später …)

Ha geschafft der Vorgang ist abgeschlossen!

Jetzt müssen wir nur noch Qt Creator davon überzeugen das statisch gelinkte qmake zu verwenden.

dazu gehen wir auf  Extras->Einstellungen->Erstellung und Ausführung->Qt Versionen und Fügen unser neues qmake (D:\Tools\qt_4_8_4\bin\qmake.exe) hinzu und versehen es mit dem Namen „Qt4.84 (Qt_4_8_4) static“ damit ist für uns kenntlich das diese Version statisch gelinkt wurde .

qmake static

diese wählen wir dann bei den Build Einstellungen aus.

Zusätzlich fügen wir bei qmake.exe ein zusätzliches Argument ein.

CONFIG+=static (hier ist wichtig das es ohne Leerzeichen geschrieben ist!)

build einstellung

wenn wir jetzt unser project egal builden landet es in dem von uns angegebenen Ordner :

D:\Qt_uebung\Egal-static-build-desktop-Qt_4_8_4_for_Desktop_-_MSVC2008__Qt_SDK__Release

unter \release finden wir nun die Datei Egal.exe.

Die Datei ist nun Ca. 7.5MB groß im Vergleich zu vorher 275kB dafür besitzt sie nun alle Abhängigkeiten und benötigt keine zusätzlichen .dll’s mehr. Nun kann die Datei so an den Kollegen ohne Probleme weitergeleitet werden.

Ein neuer Dialog

Wir möchten nun in unserem Programm einen neuen Dialog anzeigen hierzu verwende ich den „multiple inheritance approach“ das hat den Vorteil das wir auf unserem neuen Dialog weiterhin mit Slots wie on_Button_clicked() arbeiten können. Ansonsten bleibt es dem Programmierer selbst überlassen welchen der drei Ansätze er verwendet.(direct, single oder multiple)

Als erstes erstellen wir ein neues .ui Formular in unserem Fall erstellen wir einen einfachen Info Dialog also auf Datei->Neu hier wählen wir Qt Qt-Designer Formular.

anschließend werden einem ein paar Vorlagen angeboten wir wählen aber ein blankes Widget.

jetzt müssen wir noch einen Namen und den Pfad vergeben. Wir belassen ihn im Beispiel bei form.ui

schließlich wird noch gefragt zu welchem Projekt wir den Dialog gerne hinzufügen würden?

in unserem Fall Egal.pro

wir haben einen Neuen Dialog erstellt unter Formulardatein im Projektbrowser befindet sich nun form.ui ebenso wurde unter Egal.pro ein zusätzlicher Eintrag bei FORMS hinzugefügt.

Der neu erstellte Dialog ist ersteinmal blank jetzt befüllen wir ihn nach belieben mit funktionen in unserem Fall ein Info Label und einen ok Button.

Jetzt müssen wir nur noch Irgendwie unseren neuen Info Dialog angezeigt bekommen dazu erstellen wir einen neuen Action Eintrag neben dem alten Datei Eintrag wie unter Punkt Menu Bar leicht gemacht. Es muss nicht unbedingt ein neuer Menüeintrag sein sie können genausogut einen Button Checkbox oder ähnliches verwenden.

mein Unterpunkt heisst hier Über Qt ->Qt info nun fügen wir in Mainwindow die mainwindow::on_actionQt_Info_triggered() funktion ein.

In mainwindow.h fügen wir einen neuen QDialog mit einem Pointer auf den Dialog ein.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_form.h"//<<---Hier wird die automatisch erzeugte Headerdatei von form.ui eingebunden 
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
    QDialog *newform; //<--------- Pointer auf QDialog
    Ui::Form Form;    //<--------- Neuer Dialog
    QString numbOne;
protected:
    void timerEvent(QTimerEvent *event);
private slots:
    void on_actionSlider_triggered();
    void on_actionLaden_triggered();
    void on_actionSpeichern_triggered();
    void on_actionQt_Info_triggered();
    void resetall();
};
#endif // MAINWINDOW_H

Form ist der object Name den wir im Designer eigenschaften Browser ändern können.
in mainwindow.cpp fügen wir einen new QDialog ein um unsere neue form.ui im Speicher abzulegen.

void MainWindow::on_actionQt_Info_triggered()
{
    newform =new QDialog;
    newform->setModal(true);
    Form.setupUi(newform);
    newform->show();
    connect (Form.pushButton, SIGNAL(clicked()),newform,SLOT(close()));
}

Fertig ist unser neuer Dialog den connect könnten wir auch wieder über die roten Fäden bei Signal und Slots erstellen wurde hier aber per Code gemacht um zu verdeutlichen wie der zugriff auf die Elemente auf dem neuen QDialog Form erfolgt. Mit Form. können alle widgets auf dem neuen Dialog angesprochen werden mit dem Pointer newform-> können alle Funktionen von QDialog aufgerufen werden.

setModal(true) sorgt dafür das solange dieser Dialog geöffnet ist andere Dialoge nicht mehr bedient werden können.

Versuchen sie am besten die anderen beiden Approaches zur Übung auch noch aus, um den für sie am besten geigneten  Ansatz zu verwenden.

Mein eigener Slot II

Es gibt auch die Möglichkeit eigene Slots mit der Drag und Drop Methode und den roten Fäden zu erstellen.

Dazu ziehen wir eine QPushButton auf unser Formular und wählen  Signale und Slots, ziehen einen roten Faden auf das Fenster.

Es  erscheint der Verbindung bearbeiten Dialog.

mit einem Klick rechts auf Ändern  erscheint ein neuer Dialog bei dem wir durch das grüne Plus einen neuen Slot hinzufügen können.

wir nennen unseren Slot resetall() mit dem wir Den Slider un den Progressbalken wieder auf 0 zurücksetzen werden. Dazu müssen wir unseren neuen Slot in mainwindow.h einfügen

private slots:

void resetall();

und in mainwindow cpp muss der aufruf von resetall() eingefügt werden.

void MainWindow::resetall()
{
ui->spinBox->setValue(0);
ui->progressBar->setValue(0);
ui->horizontalSlider->setValue(0);
}

Wenn wir jetzt den reset Knopf drücken werden alle unsere Widgets auf 0 gesetzt.

Platzhalter oder mein Custom Widget

In vielen Fällen möchte man Eigenschaften die einem Widget aus dem Standard Portfolio fehlen hinzufügen. Dazu wähl man ein geeigntes Widget aus und erweitert dessen Eigenschaften wie man sie Benötigt. In unserem Beispiel wollen wir zum Beispiel einen Button der beim betätigen einen Sound abspielt.

Dazu erstellen wir durch Rechtsklick auf unseren Project explorer hinzufügen eine neue Headerdatei die wir wie folgt füllen: Wir erstellen eine neue Klasse Soundbutton die von QPushButton abgeleitet ist und somit alle Eigenschaften von QPushButton enthält und erweitern diese um einen neuen Slot playsound().

#ifndef SOUNDBUTTON_H
#define SOUNDBUTTON_H

#include <QPushButton>
#include <QWidget>

class soundbutton:public QPushButton
{
    Q_OBJECT

 public:
    soundbutton(QWidget *parent=0);

 public slots:
    void playsound(); //eigenen Slot erstellen

};

#endif // SOUNDBUTTON_H

anschließend benötigen wir noch den Konstruktor im Hauptprogramm mainwindow.cpp hier müssen wir auch unsere neue Headerdatei soundbutton.h einbinden, um Sound abspielen zu können verwenden wir die Qt-Klasse Qsound. Mit QSound::play können wir eine beliebige .wav Datei abspielen man muss darauf achten den Richtigen Pfad anzugeben oder man kann auch die .wav datei die man abspielen möchte in den Build Ordner kopieren. (in meinem Fall: D:\Qt_uebung\Egal-build-desktop-Qt_4_8_1_for_Desktop_-_MSVC2008__Qt_SDK__Debug)

#include "soundbutton.h"
#include <QSound>

soundbutton::soundbutton(QWidget *parent):
    QPushButton (parent)
{
    connect (this, SIGNAL(pressed()),this,SLOT(playsound()));
}

void soundbutton::playsound()
{
   QSound::play( "menu1.wav" );
}

Bissher kommt uns alles recht bekannt vor, nur  hier haben wir unseren Slot selbst erstellt und sind nicht über die autoconnect Funktion gegangen. Diesen Slot verbinden wir noch mit connect Signal pressed() oder clicked() im Konstruktor.

So jetzt kommt der Trick mit dem Platzhalter in unserem .ui File verwenden wir bis dato ja nur QPushButtons wir wollen aber soundbuttons haben. Dazu gehen wir im Designer auf einen unsere QPushButtons rechtsklick->Benutzerdefinierte Klasse… hier geben wir den Klassennamen ,die Headerdatei soundbutton.h an und wählen als Basisklasse QPushButton aus, klick auf Hinzufügen und Anwenden.

Anschließend einen QPushButton auswählen rechtsklick->Als Platzhalter für Benutzerdefinierte Klasse festlegen und hier erscheint schon unser soundbutton zur Auswahl.

Wenn wir nun einen neuen QPushButton auf unser Fenster Ziehen können wir ihn jedesmal mit rechtsklick->Platzhalter… in einen soundbutton umwandeln sehr vorteilhaft bei sehr vielen Formularen und Knöpfen.

Im Object Browser sieht man welche QPushbuttons bereits als soundbutton umgewandelt sind.

Wenn wir jetzt unser Programm erneut starten ertönt unsere ausgewählte .wav Datei bei jedem druck eines soundbuttons. Anmerkung d.R. der Close Button eignet sich hier nicht umbedingt da das Programm schneller beendet ist wie der Sound abgespielt werden kann einfach ein paar Knöpfe auf das Formular ziehen und testen.

Qt Creator Debugger unter Windows 7 installieren

Nachdem ich ein Problem hatte und nicht wusste ob meine Funktion im Programmablauf überhaupt erreicht wird, wollte ich zum ersten mal den Debugger einsetzen, sofort stellte ich fest:

mein Debugger im Qt-Creator Funktioniert nicht ich bekomme folgende Fehlermeldung:

Keiner der zum Debuggen von ausführbaren Dateien des Typs ‚…‘ geeigneten Debugger-Engines ‚CDB Engine, GDB Engine ist richtig eingerichtet.

Nachdem ich mir die Anleitung für das debuggen bei Nokia angeschaut hatte wurde klar, dass ich die Windows SDK debugging Tools benötige .

Ich habe mir die aktuellen  Install Debugging Tools for Windows as a Standalone Component heruntergeladen (kostenlos) und installiert bei der Installation habe ich nur die Debbuger Tools installiert da ich erstmal nicht weis ob ich die anderen Dinge überhaupt benötigen werde, hier gibt es allerdings mehrere Möglichkeiten die aktuelle Windows SDK herunterzuladen und zu installieren.

Anschließend habe ich noch den Symbolserver und den Debuger Pfad für CDB in QT Creator eingegeben unter Extras->Einstellungen Debugger->CDB.

Das Häckchen CDB-Konsole verwenden setzen.

Symbolpfade Einfügen->Symbol Server wird automatisch eingetragen sie müssen nur den Pfad für das Temp verzeichniss angeben Standard ist „C:\TEMP\symbolcache“

Dann noch Symbolpfade Einfügen->Hinzufügen->“Installations Pfad der SDK Debugger tool“ der pfad für die passende Windows Version muss hier ausgewählt werden 32Bit x86 bzw. 64bit x64. In dem Verzeichniss muss sich der CDB Debugger befinden Standard Pfad C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x86

Anschließend noch auf Anwenden klicken.

Wichtig ist das der CDB Debugger auch in die Toolchain mit aufgenommen wird dazu gehen wir auf Extras->Einstellungen->Erstellung und Ausführung->Toolchains. Hier wird der Compiler geklont damit wir unseren eigenen Debuggerpfad eingeben können dazu in meinem Fall: der Microsoft Visual C++Compiler 9.0(x86) MSVC auswählen und auf Klonen klicken. Da der Debugger bei der Installation nicht automatisch erkannt wurde, müssen wir ihn von Hand eintragen.

Es erscheint eine Kopie hier kann man nun den Debugger pfad eingeben „Installationspfad der SDK Debugger Tools“ Hier muss nun die 64Bit Version ausgewählt werden. Danach noch anwenden Klicken und der Debugger ist richtig in Qt eingebunden.

und nun sollte der Debugger unter Windows funktionieren. Am einfachtsen kann man das mit einem Breakpoint überprüfen.

mit einem Klick im Editor links in der entsprechnden Zeile erscheint ein Roter Punkt mit Sanduhr, dann noch der Grüne Play Button mit dem Käfer angeklickt un der debugger startet.

Wird der enstprechende Programmcode ausgeführt bleibt das Programm beim Breakpoint stehen und zeigt an dieser Stelle einen gelben Pfeil.

Zusätzlich wird in der Debugger Übersicht angezeigt wo sich das Programm befindet. Durch einen klick auf Debugging Fortsetzen ( Grüner Kreis mit Käfer), wird das programm weiter ausgeführt bis es wieder an einem Breakpoint ankommt.

Laden und Speichern Dialog

So wir haben ja in unserem Menü Balken noch einen Laden Eintrag der Noch nicht belegt ist um etwas Laden zu können müssen wir natürlich zuvor was Speichern ;-).

Also fügen wir noch einen Speichern Eintrag in unser Menü ein siehe .

Mit rechtsklick im Aktionseditor und  Slot anzeigen… wählen wir wieder als Aktion triggered() aus und erstellen je einen Slot für Speichern und Laden.

Für die Dateiverwaltung und die verwendeten Dialogboxen müssen wir folgende Includes einfügen.

#include <QFile>
#include <QFileDialog>
#include <QMessageBox>

Auf der Qt Site findet man ein gutes Beispiel für Speichern und Laden.

zusätzlich führen wir eine Variable numbOne die als Qstring declariert ist ein diese wird benötigt um unseren gespeicherten Wert mit laden wieder einzulesen. Dazu fügen wir in mainwindow.h diesen Qstring ein.

 private:
   Ui::MainWindow *ui;
    QString numbOne;

wir füllen unsere Slots mit Leben ähnlich wie im Beispiel nur das wir vorerst eine einzelne Zahl wegspeichern und keinen kompletten Datensatz.

void MainWindow::on_actionLaden_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this,
            tr("Open File"), "",
            tr("Data Text (*.txt);;All Files (*)"));
           //Voreinstellungen für den Laden_Dialog
    if (fileName.isEmpty())
             return;
         else {

             QFile file(fileName);

             if (!file.open(QIODevice::ReadOnly)) {
                 QMessageBox::information(this, tr("Unable to open file"), 
                    //Bei Fehler Fehlerdialog ausgeben
                     file.errorString());
                 return;
             }

             QDataStream in(&file);
             in.setVersion(QDataStream::Qt_4_5);

             in >> numbOne;
       //Datenstrom einlesen (numOne wurde in mainwindow.h als Qstring definiert)
             ui->spinBox->setValue(numbOne.toInt());
       //Umwandeln von numbOne in einen Integer und setzen der Spinbox
    }

}

void MainWindow::on_actionSpeichern_triggered()
{
     QString fileName = QFileDialog::getSaveFileName(this,
             tr("Save File"), "",
             tr("Data Text (*.txt);;All Files (*)"));
     if (fileName.isEmpty())
              return;
          else {
              QFile file(fileName);
              if (!file.open(QIODevice::WriteOnly)) {
                  QMessageBox::information(this, tr("Unable to open file"),
                  //Bei Fehler Fehlerdialog ausgeben
                      file.errorString());
                  return;
              }
       QDataStream out(&file);
       out.setVersion(QDataStream::Qt_4_5);
       out << ui->spinBox->text(); 
       //ausgabe in Datei.txt als Datenstrom

     }

}

Wenn wir jetzt unseren Slider einbleden und den Wert der Spinbox verändern können wir diesen als .txt Wegspeichern.

Beim Klicken auf Speichern erscheint nun ein Save Dialog ohne das wir den ganzen Dialog hätten schreiben müssen alles schon vorgefertigt.

öffnen wir das erstellte .txt File sehen wir Ein Startzeichen und die abgespeicherten Ziffern mit Abständen dazwischen das ist ok.

verändern wir nochmals den Wert der Spinbox und gehn auf Laden wird der zuvor weggespeicherte Wert eingestellt.

Ein ähnlicher Dialog wird auch zum Laden aufgerufen. So jetzt können wir schon Daten wegspeichern und wieder lesen schon ganzschön professionell 🙂

Wie wärs mit einem Timer ?

Unser Programm wächst zusehens als nächstes möchte ich die aktuelle Uhrzeit auf meinem Fenster angezeigt haben.

dazu ziehen wir ein label Widget auf unser Fenster.

Als Text geben wir 00:00:00 für unser Zeitformat ein.

Wir benötigen unsere eigene Funktion die das label per TimerEvent ständig updatet, dazu fügen wir in mainwindow.h die folgenden Zeilen in class MainWindow : public QMainWindow ein. Damit kennt Mainwindow unsere neue Funktion.

protected:
    void timerEvent(QTimerEvent *event);

Protected bedeutet das die Funktion nur in der Basisklasse und davon abgeleiteten Klassen verwendet werden kann
(Auf deutsch die Funktion kann nur in Mainwindow.cpp verwendet werden).
Anschließend geben wir in mainwindow.cpp unsere Funktion ein.

void MainWindow::timerEvent(QTimerEvent *event)
{
QTime qtime = QTime::currentTime();
QString stime = qtime.toString(Qt::LocalDate);
ui->label->setText(stime);
}

damit mainwindow.cpp auch die Timer Funktionen nutzen kann müssen wir Qtime einbinden.

#include <QTime>

Schließlich müssen wir die Zeit die als Integer geliefert wird noch in einen String umwandeln um sie als Label auszugeben. Und natürlich müssen wir den Timer starten hier wird jede 1000ms (1s) das Timer event aufgerufen.
und *tic tac* wir haben eine Uhr, nicht schlecht was ?
Komischwerweise erhalte ich ein Warning wenn ich die Qtime nicht im Mainwindow::Mainwindow initalisiere warum ist mir ehrlich gesagt nicht ganz klar daher initalisieren wir’s einfach mal. (wer hier genaueres weis bitte als Kommentar posten.) Ich verfolge eigentlich immer den Ansatz Warnings möglichst zu beseitigen wenn irgend möglich. Die erfahrung zeigt das man sich im Verlauf eine Projektes dadurch viel Ärger ersparen kann.

unser fertiges mainwindow.cpp file sieht nun so aus

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

    ui->setupUi(this);
    ui->horizontalSlider->hide();
    ui->spinBox->hide();
    connect(ui->actionBeenden,SIGNAL (triggered()), this, SLOT(close()));

    QTime qtime = QTime::currentTime(); //Timer auslesen
    QString stime = qtime.toString(Qt::LocalDate);//Timerwert als String wandeln
    ui->label->setText(stime);//Text von Label setzen
    startTimer(1000);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionSlider_triggered()
{
    if (ui->actionSlider->isChecked())
      {
        ui->horizontalSlider->show();
        ui->spinBox->show();
      }
      else
      {

        ui->horizontalSlider->hide();
        ui->spinBox->hide();
      }
}

void MainWindow::timerEvent(QTimerEvent *event)
{
  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString(Qt::LocalDate);
  ui->label->setText(stime);

}

Mein eigenes Programm Icon

Irgendwie stört mich das standard Icon von Windows für Anwendungen ich will mein Eigenes Icon haben das auch in der Startleiste und im Hauptfenster angezeigt wird. Dazu benötigen wir ein beliebiges Icon das wir uns aus dem Netz runterladen können oder mit Paint selbsterstellen. Anschließend kopieren wir die .ico Datei in unser Projektverzeichnis. Bei mir heist das icon prog3DBox.ico und sieht so aus.

Das einbinden ist etwas komplizierter. Dazu müssen wir in unserem Projektverzeichnis eine Resourcedatei anlegen indem wir mit einem Standard Texteditor in unserem Projetverzeichniss eine .rc Datei erzeugen.

ich nenne sie Egal.rc in diese Datei schreiben wir folgenden Text. (stellen sie sicher das die Datei nicht egal.rc.txt heist dies ist mir nämlich zuerst passiert und nix Icon)

IDI_ICON1               ICON    DISCARDABLE     "prog3Dbox.ico"

und speichern sie ab.

Anschließend ergänzen wir unser .pro File wie folgt.

QT       += core gui
TARGET = Egal
TEMPLATE = app
SOURCES += main.cpp\
        mainwindow.cpp 
HEADERS  += mainwindow.h
FORMS    += mainwindow.ui
OTHER_FILES += \ 
          prog3Dbox.ico 
RC_FILE = Egal.rc

Nun fügen wir noch prog3Dbox.ico zu unserem Projekt hinzu über rechtsklick auf unser Projekt->existierende datei Hinzufügen
es wird ein neuer Ordner zu unserem Projekt hinzegüfgt (Andere Dateien) der unsere .ico Datei enthält.

Wenn wir jetzt unser Programm ausführen wird das Resource file automatisch eingebunden. Voila wir haben unser eigenes Icon für unser Programm!

Wieso kann ich mein Programm nicht mehr erstellen ?

Komisch heute Morgen kann ich meine Programme nicht mehr Ausführen was ist passiert?

Mein Qt Projekt lässt sich nicht mehr kompilieren.

Der Buildprozess bleibt bei der hälfte Stehen und der Kompiliervorgang kommt bis zum starten von jom.exe.

10:05:58: Führe Build-Schritte für Projekt qextserialport aus...
10:05:58: Unveränderte Konfiguration, qmake-Schritt wird übersprungen.
10:05:58: Starte "D:\tools}QtSDK\QtCreator\bin\jom.exe"

Was zum Geier ist jom.exe??? Das Problem wurde schnell gefunden aus misteriösen Gründen wurden meine Einstellungen zum Kompilieren geändert. Unter Extras->Einstellungen->Erstellung und Ausführung

Hier wurde komischerweise das Häckchen für Jom gesetzt dies scheint auf meinem Rechner nicht zu funktionieren daher das Häckchen entfernen so das wieder nmake verwendet wird.  Und siehe da alles läuft wieder wie gehabt.

Mein eigener Slot

Als nächstes Möchte ich  einen Slider einfügen der eine SpinBox sowie einen Progressbalken und umgekehrt steuert.

dazu ziehe ich einen vertikalen Slider eine SpinBox (bei der Spinbox hab ich die Knöpfe entfernt im Eigenschaftenbrowser rechts unter buttonSymbols->noButtons) und einen Progressbar in mein .ui.

Anschließend verknüpfe ich die drei Elemente über Signale und Slots Miteinander  siehe Tabelle man muss nicht ubendingt die roten Fäden ziehen wie zuvor gezeigt mann kann auch einfach bei Signale und Slots die Verbindungen in die Tabelle eintragen.

Nun machen wir noch den Slider Eintrag in unserem Menü ankreuzbar wir wollen über den Menüpunkt die Slider Funktion ein oder ausblenden.

Beim Start sollen sie ausgeblendet sein daher schreiben wir in MainWindow::MainWindow folgendes:

ui->horizontalSlider->hide();
ui->spinBox->hide();

Jetzt klicken wir auf den Aktionseditor auf unseren Eintrag actionSlider mit rechts und sagen slot anzeigen…
wählen hier wieder triggerded() als signal.
Es wird folgender Code automatisch erstellt :
in mainwindow.h wird unter private slots ein Eintrag ertellt

private slots:
void on_actionSlider_triggered();

und im mainwindow.cpp wird ebenfalls ein Eintrag erstellt den wir noch mit Leben füllen:

void MainWindow::on_actionSlider_triggered()
{
    if (ui->actionSlider->isChecked())
      {
        ui->horizontalSlider->show();
        ui->spinBox->show();
      }
      else
      {

        ui->horizontalSlider->hide();
        ui->spinBox->hide();
      }
}

isChecked überprüft ob unser actionSlider ein häckchen hat oder nicht show und hide sind denke ich selbsterklärend.
on_actionSlider_triggered() impliziert bereits das triggern des Menüeintrages man muss also nicht unbedingt immer über connect(bla bla bla…) gehen.

Video Tutorial (englisch)

Ein sehr gutes und ausführliches Video Tutorial zu Qt

kann für das Tutorial erstmal Übersprungen werden und später angeschaut werden, ist aber auf jedenfall hilfreich.

Menu Bar leichtgemacht

Als Nächstes möchte ich noch einen Menü Balken für meine Anwendung haben dazu gehen wir in den Designer und klicken einfach auf die schon vorhandene menubar in der ui. Will man ein Objekt komplett entfernen geht das durch löschen im Objekt explorer.

Durch einfach anklicken und Eintragen der gewünschten Menüeinträge erstellt man sogenannte aktions die von der Namenskonvention immer actionMenüeintrag heißen, auf diese kann man dann im Programmcode leicht zugreifen. Es können auch Untermenüs nach belieben erstellt werden.

Wir erstellen nun drei Menüeinträge Datei->laden Datei->Slider Datei->beenden

Die erstellten Menüeinträge erscheinen im Aktionseditor und können hier mit beliebigen Icons belegt oder auch ankreuzbar gemacht werden.

Um ein Tastenkürzel zuzuweisen klickt man auf Tastenkürzel und drückt die Gewollte Abkürzung z.B STRG+B  oder aber wir müssen erstmals im Editor Code hinzufügen:

in der Datei mainwindow.cpp unter der Funktion MainWindow::MainWindow fügen wir ein:

ui->actionBeenden->setShortcut(tr("CTRL+B"));

Dies weist dem Menüeintrag Beenden das kürzel CTRL+B zu , und was bedeutet tr? Tr wird nur benötigt wenn man vorhat sein Programm auch in anderen Sprachen zur verfügung zu stellen. Alle Strings können dann später übersetzt werden wie das funktioniert weis ich momentan auch noch nicht so genau dies ist aber offensichtlich einer der großen Vorteile von QT.

So jetzt verknüpfen wir die Menüeinträge noch mit Funktionen bzw. Slots einfachster Fall ist wiedermal das Beenden.

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->actionBeenden->setShortcut(tr("CTRL+B"));
    connect(ui->actionBeenden,SIGNAL (triggered()), this, SLOT(close()));
}
MainWindow::~MainWindow()
{
    delete ui;
}

Danach Starten wir unser Programm


Nun können wir unsere Anwendung auch über das Menü beenden *freu*. Mit Strg+B kann jetzt auch beendet werden.

Qt Creator

Irgendwie ist in dem angegebenen Tutorial alles anders da wir ja den Qt Creator verwenden ? Doch keine Panik vieles ist analog dazu und hilft uns beim Einstieg.

Wir starten mit einem ersten Knopf da wir Faul sind benutzen wir natürlich gleich Signals und Slots die wir aus dem Tutorial kennen aus. Wir sind nur so clever das wir gleich das Eingebaute Drag&Drop Verfahren benutzen und nicht alles von Hand schreiben.

Im Designer (doppelklcik auf .ui file) kann man per drag&drop einfach ein Widget, so heissen die Dinger hier, auf unser Fenster ziehen.

danach klicken wir auf Signale und Slots bearbeiten.

und ziehen eine Rote Schnur vom Button auf das leere mainwindow.

folgendes Fenster erscheint.

wir klicken nun das Häckchen Signale und Slots von Qwidgets anzeigen noch an und sehen die verfügbaren Slots.

z.B wählen wir Signal clicked() und Slot close()

entspricht in etwa dem Programm text aus dem Tutorial

connect(ui->Pushbutton, SIGNAL(clicked()), this, SLOT(close()));

nur alles ohne eine einzige Zeile Code selber zu tippen, man bin ich faul… 🙂

Wenn wir nun starten „grüner Pfeil“ haben wir unser Erstes Programm ein Knopf der unser Fenster wieder schließt *freu*