QT von anderer Klasse aus auf ui zugreifen

ChriMo

Mitglied
Hi
Vereinfacht dargestellt:
Habe ein ui mit einem QLabel.
Vom Ablauf her:
Nach Programmstart ui->label->setText("A");
und dann ui->label->setText("B");

Ist kein Problem (Klar, dass man nur "B" sieht - wie schon gesagt vereinfacht dargestellt)

Nun möchte ich jedoch, dass ->label->setText("B"); aus einer Klasse "Teil_B" heraus aufgerufen wird.

Und als Draufgabe: Pushbutton, der setText("C") bewirkt und dessen Slot in "Teil_B" beheimatet ist.

Habe Folgendes versucht:
mainwindow.h: Ganz normal, wie es der Creator erzeugt
--------------
teil_b.h:

#ifndef B_H
#define B_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

class Teil_B : public QObject
{
Q_OBJECT
public:
explicit Teil_B(Ui::MainWindow *dasUi);

private slots:
void on_pushButton_clicked();

private:
Ui::MainWindow *UIVonMain;

};

#endif // B_H
-----------------
mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "teil_b.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

ui->label->setText("A");
// ui->label->setText("B"); Das in Klasse "Teil_B" verschieben.
// Und hier sollte Teil_B aufgerufen werden. Doch wie?
Teil_B (*ui) ; //Wird anscheinend ignoriert

}


----------------------
teil_b.cpp:

#include "teil_b.h"

Teil_B::Teil_B(Ui::MainWindow *dasUi)
{
qDebug()<<"B gestartet";

UIVonMain = dasUi;
UIVonMain->label->setText("B");

}

void Teil_B::eek:n_pushButton_clicked()
{
qDebug()<<"geklickt";
UIVonMain->label->setText("C");
}


Das Programm wird zwar ausgeführt, Teil_B jedoch anscheinend vollkommen ignoriert:
Nicht mal qDebug()<<"B gestartet"; wird angezeigt.


LG
ChriMo
 
Ehrlich gesagt verstehe ich dein Problem nicht so ganz (liegt teilweise am Fehlen von mainwindow.h). Das UI sollte nicht von Teil_B gesteuert werden, denn nur MainWindow verwaltet es.

Nun möchte ich jedoch, dass ->label->setText("B"); aus einer Klasse "Teil_B" heraus aufgerufen wird.
C++:
class Teil_B : public QObject
{
    Q_OBJECT
public:
    Teil_B() = default;
    Teil_B(QLabel* label, QPushButton* button)
    {
        setLabel(label);
        setButton(button);
    }

    void setLabel(QLabel* label) { m_label = label; m_label->setText("B"); }
    void setButton(QPushButton* button) { m_pb = button; connect(m_pb, SIGNAL(clicked()), this, SLOT(onPushButtonClicked())); }

}
private slots:
    void onPushButtonClicked()
    {
        //Whatever
    }
private:
    QLabel* m_label;
    QPushButton* m_pb;
};


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

ui->label->setText("A");
m_teil_B.setLabel(ui->label);               //Member in der Form Teil_B m_teil_B;
m_teil_B.setButton(ui->pushbutton);
}

Dein Problem ist, dass du ja irgendeinen Konstruktor hinschreibst, aber kein zugehöriges Objekt erstellst. Generell scheinst du aber ein ziemlich kompliziertes Management im Sinn zu haben. In der Regel ist es am klügsten, genau eine Klasse die Anzeige machen zu lassen, und der Rest macht die echte Arbeit.

Gruss
cwriter
 
Der Grund ist, dass es sich hierbei um ein ziemlich komplexes bauphysikalisches Programm handelt:
Verschiedene Berechnungsteile, die zum Teil voneinander abhängen, jedoch mit einer gemeinsamen Darstellung (Sowohl Ergebnisse als auch Eingaben), die komplizierte Struktur ergibt sich daraus.
Wie bekomme ich es hin, dass es so funktioniert? - Dann wär ich happy.

LG
Christoph
 
Verschiedene Berechnungsteile, die zum Teil voneinander abhängen, jedoch mit einer gemeinsamen Darstellung (Sowohl Ergebnisse als auch Eingaben), die komplizierte Struktur ergibt sich daraus
Ok, also hast du verschiedene Berechnungsteile. Willst du parallelisieren? Dann geht es so "offiziell" nicht. Oft funktioniert(TM) es zwar, aber Qt wird dich mit Warnungen eindecken, wenn verschiedene Threads auf das GUI zugreifen. Die Lösung da: Signals & Slots. (Signal wird von Worker-Threads emittiert und mit einem Slot im Displaythread verbunden).
Willst du nicht parallelisieren? Dann hängt deine GUI wahrscheinlich sehr oft, vor allem aber fehlt ein guter Grund, die Arbeit in Teile zu spalten.



Wie bekomme ich es hin, dass es so funktioniert?
Wie denn?
Was funktioniert an meinem Beispielcode nicht?

Das Problem bei deinem Code ist schlicht, dass dein freistehender Konstruktor nichts machen kann, weil er keiner Instanz zugeordnet bzw., falls es ein Member der Klasse sein soll, schlicht schon initialisiert ist. Also entweder erstellst du eine lokale Instanz ("Teil_B b(ui)") oder du hast eine Member und reinitialisierst durch Kopie ("m_b = Teil_B(ui)") oder du machst es wie im Beispiel mit settern.

Am besten überdenkst du dein Design aber komplett. Ich habe schon ein paar mal mit Qt gerarbeitet und du kannst mir glauben, dass die UI immer von Anfang an entkoppelt sein sollte. Es gibt sonst immer irgendwelche Probleme.

Gruss
cwriter
 
Wenn man Qtabwidgets verwendet, schreibt QT den Code leider für alle Tabs in die selbe Klasse.
Ich habe z.B. in tab1 Tabellen etc. und in tab2 auch Tabellen etc.
Und als Ergebnis einen Haufen mit Code für alle.
Ich möchte für jeden tab eine eigene Klasse haben, in der auch der ui-Zugriff auf die Objekte des Tabs möglich ist.

LG
ChriMo
 
Wenn man Qtabwidgets verwendet, schreibt QT den Code leider für alle Tabs in die selbe Klasse.
Nope, eigentlich nicht, QTabWidget hat einzelne QWidgets als Tabs. Diese kannst du auch mit einer eigenen Klasse ersetzen.


Und als Ergebnis einen Haufen mit Code für alle.
Ein Haufen Code ist ein Ergebnis? Ich verstehe nicht, was du meinst.

Ich möchte für jeden tab eine eigene Klasse haben
=> Eigenes QWidget

in der auch der ui-Zugriff auf die Objekte des Tabs möglich ist.
Nein, willst du nicht. Wie soll dann die Hierarchie aussehen? Das MainWindow ruft eine Klasse auf, die dann zurück zum MainWindow geht und ein anderes Element aufruft, usw.? Und in der Zwischenzeit wird das Fenster nicht neu gezeichnet?

Nochmals: Logik und Darstellung müssen immer getrennt sein. Du kannst im MainWindow per Signal die Logik starten. Ist diese fertig, emittiert sie ein Signal, dass sie fertig ist, und die verbundenen Widgets ihre Daten ziehen können.

Gruss
cwriter
 
Oh weh, da hab ich die QTabWidgets falsch verstanden:
Habs im Designer kreiert, über re Maustaste tabs hinzugefügt und diese mit Dingen aus der Widget-Box gefüllt.
Dann mit re-Maus Slots hinzugefügt, und die landen alle in der Klasse, in der auch das QTabWidget ist, egal um welchen tab es sich handelt.
Das meinte ich mit "Haufen" - meinen Code hab ich auch noch dazu geschrieben.
Der "Haufen" hat mich gestört, irgend jemanden in irgend einem Forum auch, und der hat die Antwort bekommen, dass das eben so ist und nicht anders geht.
Wo das war, weiß ich nicht mehr, jedenfalls hat dort niemand widersprochen und ich hab es unreflektiert übernommen.
Danke, dass Du so prompt darauf reagiert hast und durch meinen Beitrag der Mist nicht weitergegeben wird.
Hab ich es richtig verstanden:
Im Designer erstelle ich ein QTabWidget ohne Tabs
Ich erzeuge neue Designer-Formularklasse/Widget und füge diese per Code (->addTab(new ....) ) im QTabWidget ein.
Der Weg, im Designer erstellten Tabs Klassen zuzuordnen ist nicht möglich?

LG
ChriMo
 
Der Weg, im Designer erstellten Tabs Klassen zuzuordnen ist nicht möglich?
Doch, über Rechtsklick auf das QTabWidget, dann "Page 1 of 2" (Zahlen können abweichen; es ist immer der Selektierte Tab (weiss nicht, wie es auf Deutsch angeschrieben ist)), und dann auf "Promote to", wo du eine andere Klasse angeben kannst.

Danke, dass Du so prompt darauf reagiert hast und durch meinen Beitrag der Mist nicht weitergegeben wird.
Immer gerne. Dafür ist ja das Forum da :)

Dann mit re-Maus Slots hinzugefügt, und die landen alle in der Klasse, in der auch das QTabWidget ist, egal um welchen tab es sich handelt.
Die Slots von Qt sind tatsächlich viel mächtiger, als der Designer es vermuten lässt. Aber ja: Mach soviel wie möglich im Designer. Manuell geht es auch, aber man hat viel länger damit.

Gruss
cwriter
 
Zurück