Zugriff auf Ui-Elemente einer anderen Klasse



  • Hallo Leute,

    ich habe in einer mainwindow.ui Datei mehrere line_Edit's eingefügt. Wie kann ich am effektivsten von einer anderen Klasse auf diese line_Edit's zugreifen um deren Zustand zu änderen. Ich möchte z.B. von einer anderen Klasse aus den Befehl geben

    ui->line_Edit->setEnabled(true).
    

    Danke im Voraus



  • Vielleicht eine "dämliche" Frage, aber was sind line_Edit s? In welchem Kontext steht diese Frage?



  • Indem du in deiner MainWindow Klasse entsprechende Funktionen dafür anbietest die von der anderen Klasse aufgerufen werden können.
    Da es sich wohl um Qt handelt könnte man das auch über Signal-Slot Verküpfungen lösen.



  • Wenn ich richtig verstehe geht es um generellen Zugriff, nicht nur um ein oder zwei spezielle Funktionen. Da würde ich die ui und die lineedits einfach public machen, dann kannst du auch darauf zugreifen.



  • @Mittagspause: Das widerspricht dem Kapselungsprinzip.



  • @Th69 Weiß ich. Aber im Einzelfall macht es meiner Meinung durchaus Sinn, dem Kapselungsprinzip zu wiedersprechen. Gerade bei der Arbeit mit GUI Frameworks.



  • @Mittagspause sagte in Zugriff auf Ui-Elemente einer anderen Klasse:

    @Th69 Weiß ich. Aber im Einzelfall macht es meiner Meinung durchaus Sinn, dem Kapselungsprinzip zu wiedersprechen. Gerade bei der Arbeit mit GUI Frameworks.

    Ich wollte diese Ausnahme speziell für GUIs auch gerade zur Diskussion stellen. Man hat es bei GUI-Objekten oft nur mit losen Beziehungen zu tun, die nicht selten lediglich durch das Layout bestimmt werden. public-Zugriff ermöglicht da eine wesentlich flexiblere Handhabung dieser Objekte - vor allem weil man sich den ganzen Boilerplate der Zugriffsfunktionen sparen kann.

    Ansonsten bin ich auch starker Befürworter einer sauberen Kapselung. Zum Beispiel bei der Implementierung des Datenmodells aus dem das GUI seine Daten bezieht. Beim GUI selbst halte ich jedoch möglichst freien Zugriff kreuz und quer für eine gar nicht soo schlechte Idee 🤔

    P.S.: Ist lange her, dass ich was mit Qt gemacht habe, aber macht der Qt Designer (oder wie der heisst) nicht eh schon alle Widgets in dem Fenster public, wenn man die im Editor layoutet? Und was ist die Qt-typische Vorgehensweise? Ich glaube nicht, dass die für jede kleine Methode wie setEnabled Signals/Slot-Mechanismen anbieten, oder?



  • @Finnegan sagte in Zugriff auf Ui-Elemente einer anderen Klasse:

    P.S.: Ist lange her, dass ich was mit Qt gemacht habe, aber macht der Qt Designer (oder wie der heisst) nicht eh schon alle Widgets in dem Fenster public, wenn man die im Editor layoutet? Und was ist die Qt-typische Vorgehensweise? Ich glaube nicht, dass die für jede kleine Methode wie setEnabled Signals/Slot-Mechanismen anbieten, oder?

    Der Qt Designer erstellt eine separate Klasse in dem alle UI Elemente als public member definiert sind. (name <widget_name>_ui)
    Und eine Instanz dieser Klasse ist im Beispiel Zeile von ChrisLA86 die "ui" variable.

    Bezüglich Signals/Slots. Alle Methoden, können seit Qt5 als "Slot" eines Signals genutzt werden und müssen nicht explizit in der Deklaration als QT_SLOT (zusätzlich zu public/protected/private) markiert werden.
    Denn mit Qt5 wurde ein neue connect mechanismus eingeführt worüber man dann auch lambdas an ein signal binden kann. Das ganze ist ähnlich der funktionalität einer std::function
    https://doc.qt.io/qt-6/signalsandslots-syntaxes.html



  • Man sollte trotzdem nicht direkt auf UI-Elemente zugreifen, sondern Datenbindung (data binding) verwenden, s. z.B. Qt equivalent of .NET data binding?
    Wenn man z.B. ein Optionsfenster hat, so sollten die Optionen in einer eigenen Logik-Klasse gekapselt sein und die Anwendung dann diese Optionswerte ändern - und das Fenster verwendet dann die gleiche Klasseninstanz zur Anzeige und zum Ändern.



  • Hey Leute, erstmal vielen Dank für die Antworten. Ich habe jetzt ein bisschen rumprobiert und habe jetzt erstmal die folgende Lösung gefunden. Sagt mal bitte was ihr davon haltet, da ja das Thema Signals/Slots hier aufkam, ich das jetzt aber ohne gemacht habe. Ich denke es macht doch auch kein großen Unterschied, oder? Da wenn mit Signals/Slots gearbeitet wird, das Programm doch eigentlich genau das Gleiche macht??? Im Endeffekt verbindet man doch nur die Methoden miteinander, die ja auch so aufgerufen werden. Oder arbeitet das Programm mit Signals/Slots effizienter?

    MainWindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <vectorklasse.h>
    #include <spielfeld.h>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
        vectorklasse *zeigerAufVector;
        spielfeld *neuesFenster;
        spielfeld *ptr;
    
        Ui::MainWindow* getUi();
    
    
    
    
    private slots:
        void on_pushButton_clicked();
    
        void on_lineEdit_selectionChanged();
    
        void on_lineEdit_3_selectionChanged();
    
        void on_lineEdit_2_selectionChanged();
    
        void on_lineEdit_4_selectionChanged();
    
        void on_lineEdit_5_selectionChanged();
    
        void on_lineEdit_6_selectionChanged();
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    MainWindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "spielfeld.h"
    #include <vectorklasse.h>
    #include <algorithm>
    #include <spielfeld.h>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        srand(time(0));
        ui->setupUi(this);
    }
    
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    Ui::MainWindow* MainWindow::getUi()
    {
        return ui;
    }
    

    spielfeld.cpp

    void spielfeld::on_pushButton_clicked()
    {
        MainWindow *ptrMain = (MainWindow*)QApplication::topLevelWidgets().first();
        Ui::MainWindow *uiMain;
        uiMain = ptrMain->getUi();
        
        uiMain->lineEdit->setDisabled(true);
    }
    


  • öhm da MainWindow instanzen von spielfeld hält und vermutlich auch erzeugt, könntest du direkt eine "referenz" (und hier ist nicht unbedingt eine C++ referenz gemeint) den spielfeld Instanzen beim erstellen übergeben.
    Dadurch sparst du dir solchen code, der fehleranfällig ist, falls das erste toplevel fenster nicht mehr eine MainWindow instanz ist.

    MainWindow *ptrMain = (MainWindow*)QApplication::topLevelWidgets().first();
    

    Ansonsten wäre es nicht besser, wenn die MainWindow instanz sich auf die button clicked events selbst bindet um dann elemente entsprechend anzupassen?
    Oder die Spielfeld Instanz definiert selbst signals welche mehr dem context entsprechen.

    z.b. Der Button, dessen clicked signal spielfeld::on_pushButton_clicked aufruft, hat die Bedeutung "Aktion X wurde gestartet".
    Dann wäre es besser (unter anderem aus sicht des verständnisses) wenn spielfeld ein signal definiert, welches aussagt, dass "Aktion X" gestartet wurde.
    Wenn es ein eigenes signal ist, dann ist es egal wie genau der zustand "Aktion X wurde gestartet" erreicht wurde.
    Eventuell könnte es ja auch sein, dass dieser Zustand neben dem Button durch die logik der spielfeld klasse ausgelöst werden könnte.

    Des weiteren ist dadurch die spielfeld instanz entkoppelt von einer "main window" instanz und kann dadurch auch in anderen situationen genutzt werden, wo keine "MainWindow" instanz existiert.
    Zusätzlich muss spielfeld nicht wissen was gemacht werden muss wenn "Aktion X wurde gestartet" signalisiert wird, denn das sollte nicht die Aufgabe der spielfeld klasse sein.



  • @firefly kannst du mir erklären was du mit "referenz" übergeben meinst?



  • und im ganz Allgemeinen, kann mir jemand Lektüre empfehlen um mehr über das Verhältnis von Instanzen untereinander zu lernen bzw. wie man sie sinnvoll entkoppelt?


Anmelden zum Antworten