PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Qt: Gui von Hauptprogramm trennen



Sector1379
10-06-2007, 22:56
Hallo zusammen,

ich fange gerade erst an mit GUI Programmierung, aber ich habe eine Frage bei der ich einfach nicht weiter komme. Unzwar wie Programmiert man eine GUI (also bei mir aktuell QT) und trennt diese von Hauptprogramm ?????

Ich habe schon alles abgesucht nach Informationen aber ich blick einfach nicht druch wie ich das machen soll. Z.b muss ich doch an die connects andocken mit funktionen.

Da kann ich doch gar nicht ohne Hauptprogramm arbeiten, den genau das stellt mir ja die function bereit................ also wie ihr seht scheine ich das was grundlegendes nicht verstanden zu haben und ich fände es spitze wenn mir vielleicht einer von euch an einen kleinen beispiel zeigen könnte was man genau darunter versteht..........

anda_skoa
12-06-2007, 15:19
Damit ist nicht gemeint, dass Hauptprogramm und GUI nicht gegenseitig Funktionen aufrufen, sondern dass sie beide, oder zumindest der Hauptteil, nicht weiß, wessen Funktionen er aufruft.

D.h. man kann die GUI austauschen, ohne am Hauptteil etwas ändern zu müssen.

Bei Qt kann man das relativ leicht mit Signals&Slots machen, d.h. wenn der Kern eine Interaktion mit dem Benutzer wünscht, sendet er ein entsprechende Signal aus. Dabei ist dem Kern dann egal, an welche Art von GUI du das Signal verbunden hast.

Allgemeinere Möglichkeiten sind abstrakte Klassen bzw. Interfaces als Schnittstellen, d.h. man hat eine Klasse mit virtuellen Methoden und der Kern macht an einem Objekt, da von dieser Klasse ableitet, seine Aufrufe, ohne wissen zu müssen, welche Klasse das Objekt konkret ist.

Beispiel:


class MessageHandler
{
public:
virtual void showMessage(const QString& message) = 0;
};

class Kern
{
public:
void registerMessageHandler(MessageHandler* handler) { m_messageHandler = handler; }

void foo() { m_messageHandler->showMessage("foo() called"); }
private:
MessageHandler* m_messageHandler;
};

class QtMessageHandler : public QTextEdit, public MessageHandler
{
public:
virtual void showMessage(const QString& message)
{
append(message);
}
};

class ConsoleMessageHandler : public MessageHandler
{
virtual void showMessage(const QString& message)
{
std::cout << message.local8Bit().data << std::endl;
}
};
// irgendwo im Programm
Kern kern;

QtMessageHandler handler1;

kern.registerMessageHandler(&handler1);
kern.foo();

ConsoleMessageHandler handler2;

kern.registerMessageHandler(&handler2);
kern.foo();

Die Klasse Kern ist dabei von der GUI abgekoppelt, weil sie mit dem Interface MessageHandler arbeitet, das beliebigt implementiert sein kann

Ciao,
_

Sector1379
13-06-2007, 00:11
Vielen vielen dank für die tolle erklärung :cool:
Ich habe mich mal dran gemacht und ein mini programm geschrieben an dem ich dich mal fragen wollte ob ich alles richtig verstanden habe. Das Programm ist super simpel
es soll einfach ein text eingegeben werden und dieser wird eingelesen und dann in der unteren Zeile ausgegeben. Hier mal der Code:

Gui.h


#ifndef _GUI_
#define _GUI_
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QGridLayout>
#include <QWidget>
#include <QLineEdit>
#include <QLabel>
#include <QString>
#include "func.h"

class QtGui: public QWidget, public Func{

Q_OBJECT

public:

QtGui(QWidget *parent = 0);

private slots:
void getInput();

private:
QPushButton *quit;
QPushButton *read;
QGridLayout *layout;
QLineEdit *in;
QLineEdit *out;
QLabel *name_in;
QLabel *name_out;
};

#endif


Gui.cpp


#include "Gui.h"

QtGui::QtGui(QWidget *parent)
:QWidget(parent), Func()
{

quit = new QPushButton(tr("Quit"));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));

read = new QPushButton(tr("Read"));
connect(read, SIGNAL(clicked()), this, SLOT(getInput()));

in = new QLineEdit;
out = new QLineEdit;

name_in = new QLabel("IN:");
name_out = new QLabel("OUT:");

layout = new QGridLayout;
layout->addWidget(name_in, 0, 0);
layout->addWidget(in, 0, 1);
layout->addWidget(name_out, 1, 0);
layout->addWidget(out, 1, 1);
layout->addWidget(read, 2, 0);
layout->addWidget(quit, 2, 1);
setLayout(layout);

}

void QtGui::getInput(){

QString te;
const char *huh;

te = in->text();
QByteArray ba = te.toLatin1();
huh = ba.data();
setTex(huh);
out->setText(getText());
}


Func.h


#ifndef _FUNC_
#define _FUNC_
#include <iostream>
#include <string>

using namespace std;

class Func{

public:
Func();
char *getText();
void setTex(const char *te);

private:

char *text;


};

#endif


Func.cpp


#include "func.h"

using namespace std;

Func::Func(){
}

char* Func::getText(){

return text;

}

void Func::setTex(const char *te){

int len = strlen(te) + 1;
text = new char[len];
strcpy(text, te);
}


main.cpp


#include "Gui.h"
#include <iostream>
#include <string>
#include "func.h"

using namespace std;

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

QApplication app(argc, argv);
QtGui trennen;

trennen.show();


return app.exec();
}



So wie man unschwer erkennen kann ist es wirklich nix wildes was ich da gemacht habe, mir gehts halt nur ums prinzip und das ich das wirklich verstehe.

Also die Func Klasse stellt bei mir die Kern klasse da diese soll nicht verändert werden. Die Gui ist klar greift auf die funktionen von Func zurück und in der main wird nur ein Object nämlich die gui erstellt und damit hat man dann alle funktionalitäten.

Ist das so von mir richtig aufgefasst worden oder hätte ich anstatt der vererbung lieber eine delegation machen sollen ????

RHBaum
13-06-2007, 14:36
Unzwar wie Programmiert man eine GUI (also bei mir aktuell QT) und trennt diese von Hauptprogramm ?????
Das solltest DU mal genauer erlaeutern, was genau Du meinst !

Richtig "Trennen" kann man Hauptprogramm und GUI ned wirklich, weil die GUI zeigt (zumindest sollte normalereise es so sein) Inhalte aus dem Hauptprogramm an :-)

Trennen wird eher im Sinne von Abstraktion verwendet.

Trennen kann man auf executable Sicht sehen .... du hasst unterschiedliche executables.
Beispiel eine LAMP anwendung
- Datenbank(mysql daemon)
- Apache mit php / perl / java engine (Logic - Schicht) (apache daemon)
- Browser mit oder ohne Java / php script erweiterung (mozilla, oder IExplorer.exe )
in dem falle koennten sogar alle 3 komponenten auf unterschiedlichen rechnern laufen. Verbunden sind sie soweiso immer, in dem fall ueber IPC Protokolle (TCP/IP - HTML).

Man kann es aber auch Sicht von Uebersetzungseinheiten .... Sprich du hasst fuer die Datenhaltung / Logic / GUI unterschiedliche Module, die du austauschen kannst. Die Module werden dann klassischerweisse(also meistens) als shared Objects / dlls (InProzess) ausgefuhrt, executable hasst du nur noch eines, und das laed sich die module zu, verbunden sind die Schichten dann nur noch ueber (hoffentlich abstrakte) Schnittstellen.
Wobei Externe Prozesse (ExtProzess) Loesungen (wie 1. Beispiel) natuerlich auch module sind.


Von Trennung redet man auch, wenn man auch nur saubere Schnittstellen (abstract) einfuehrt (meist aber dann soweiso mit einer Modularisierung im hintergrund).

Frueher in der Informatik redete man oft vom 3 Schicht Modell, nicht zuverwechseln mit dem gleichnamigen Modell zur Altersvorsorge unserer Bundesregierung :-) und dem OSI Modell .
Viel spass beim googeln :-)

Ciao ...

anda_skoa
13-06-2007, 17:20
Ist das so von mir richtig aufgefasst worden oder hätte ich anstatt der vererbung lieber eine delegation machen sollen ????

Ja, wäre besser.

Es könnte zum Beispiel einen Zeitpunkt geben, wo du "Func" auch gerne als QObject haben möchtest und dann geht auf einmal die Ableitung nicht mehr, weil man nicht zweimal von QObject ableiten darf.

Ciao,
_

Sector1379
13-06-2007, 20:20
Hi anda,

sag mal ist es eigentlich generell besser eine Delegation zu machen. Ich meine mal mit bekommen zu haben das es besser ist für die Speicherverwaltung.

Kannst du das bestätigen oder kommt das immer drauf an ??

anda_skoa
13-06-2007, 22:12
Das ist Software Entwicklung, da gibt es keine generell richtigen Sachen :)

Eine Delegation hat z.B. den Nachteil, eine Indirektion zu sein, könnte also teilweise bischen weniger performant werden (allerdings normalerweise vernachlässigbar)

Ein gute Richtwert ist, keine Ableitung zu machen, wenn man es nur wegen dem Benutzen von Funktionalität gemacht hätte.

In deinem Beispiel verbietet sich die Ableitung, weil das praktisch das Gegenteil von der als Ziel gesetzten Trennung ist.

Eine Delegation erlaubt dir auch, den Zeitpunkt der Erzeugung anders zu variieren, d.h. du hast dann zum Beispiel die Möglichkeit, ein leeres Hauptfenster zu erzeugen und sofort anzuzeigen und erst danach Schrittweise den Kern bzw. mehrere Kernkomponenten.

Aber er ist natürlich mehr Aufwand, daher kann man, meiner Meinung nach, keine allgemeine Richtigkeit draus machen.

Hängt ja auch davon ab, ob man nur schnell einen Prototyp braucht, oder an etwas arbeitet, was dann lange erweiterbar und wartbar sein soll.

Beim Thema Softwarearchitektur sollte man immer sowohl Vorteile als auch Nachteile von Lösungmöglichkeiten betrachten.

Ciao,
_