qt i przekazywanie wartości między formami

0

Witam!

Próbuje w Qt przekazać pewne dane z forma głównego do forma generowanego po naciśnięciu przycisku na formatce głównej. Tak jak mi ktoś poradził z tego forum już wcześniej muszę to zrobić za pomocą wskaźników, aby z poziomu formularza generowanego przyciskiem mieć dostęp do danych forma głównego ale nie wiem czy i jak to poprawnie wykonać.

Pod przyciskiem na oknie głównym mam coś takiego:

Form2 *f2 = new Form2();
        f2->oknoGlowne=this;
        f2->show();

A konstruktor tego formularza f2 ma taki kod:

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

    Ui::Form1 *oknoGlowne;

    //pożądane dane z Form1 wywołuje w taki sposób (z rzutowaniem):
    (Form1)oknoGlowne.zmienna1;
}

W pliku nagłówkowym Form2, w sekcji public jak zadeklaruje wskaźnik oknoGlowne to kompilator zgłasza że takiej zmiennej w ogóle nie widzi. Nie wiem też czy to będzie miało znaczenie ale zmienne, które chce odczytywać w Form2 są zadeklarowane jako publiczne w pliku nagłówkowym Form1.

Wszystko to daje takie oto błędy:

błąd "oknoGlowne" : nie jest elementem czonkowskim "Form2"

błąd po lewej ".zmienna1" musi by† typ struct/union
typ to "Ui::Form1 *"
czy zamiast tego mia by† uľyty "->"?

Jak to interpretować i zrobić aby było dobrze? Pomysły mi się już skończyły niestety, dlatego też proszę Was bardzo o pomoc :/

0

Jak ja miałem problem z przekazywaniem pewnych danych między formami to powiedziano mi że rozwiązaniem w Qt są sygnały i sloty.
W klasie z której chcesz coś przekazać piszesz a następnie emitujesz sygnał a w klasie głównego okna piszesz slot który te dane odbiera i później łączysz sygnał ze slotem

connect( form2, SIGNAL( dane_do_przekazania( jakies_parametry ) ), form1, SLOT( funkcja_przetwarzajaca_dane( jakies_parametry ) ) );
0

hmm wiem, że są sygnały i zloty, jednak w moim przypadku musiał bym bardzo dużo slotów i sygnałów tworzyć i wysyłać a jest to jedno, jedyne miejsce w programie gdzie musze coś przekazać do nowego forma i chciałbym uniknąć tego stosując wskaźnik do obiektu, którym ma być okno główne programu na którym ustawiam pewne wartości. pomożecie? :)

0
sim-ns napisał(a):

hmm wiem, że są sygnały i zloty, jednak w moim przypadku musiał bym bardzo dużo slotów i sygnałów tworzyć i wysyłać

Eem a dlaczego tak? Możesz sprecyzować te ograniczenia? Możesz sobie przecież utworzyć jeden sygnał który wyśle wskaźnik do obiektu formularza ze wszytkimi danymi.

0

skoro tak mówisz to tak musi być :) nie jestem aż tak wtajemniczony w sygnały i sloty jeszcze w takim razie żeby wiedzieć że można to załatwić jednym slotem :/

Spróbuje użyć slotów i sygnałów...

0

Możesz sobie zadeklarować np taki sygnał:

void AllData(Form *form); 

A potem użyć go np tak:

emit AllData(this);

Oczywiście to tylko przykład, z przekazywaniem this zawsze trzeba uważac. Możesz sobie zaagregować dane do osobnego obiektu i jego wysyłać. Możliwości jest sporo, ciężko mi sobie wyobrazić sytuację w której musiałbyś stworzyć jakąś nie wiadomo jak dużą ilość sygnałów i slotów żeby przesłać dane z formularza.

0

nie, nie ok

wydawało mi się jak to pisałem że jeden sygnał może przekazać jedną daną/zmienną a mam min. 4 zmienne, które chce przekazać między formami, ale teraz już wiem że wystarczy do tego jeden sygnał i slot jednak póki co próbuje tak owy stworzyć aby przekazać to co chce.

0

Ok, mniej więcej załapałem juz chyba sygnały i sloty, jednak zastanawia mnie jedna rzecz, a mianowicie zrobiłem dwie funkcje (zadeklarowane jako 2 sloty - jeden w oknie głównym, drugi w nowym oknie) odczytującą wartości zmiennych z okna głównego i ustawiającą te wartości funkcje w drugim oknie, aczkolwiek po drodze tworzę bardzo dużo zmiennych dodatkowych, i nie bardzo widzę sens takiego działania. Pewnie robię to źle i bardzo was proszę o pomoc:

void MainWindow::dane(QString tmp_z1, QString tmp_z2, QString tmp_z3, QString tmp_z4)
{
    tmp_z1 = z1;
    tmp_z2 = z2;
    tmp_z3 = z3;
    tmp_z4 = z4;
}
void Form2::odczytDanych(QString temp_z1, QString temp_z2, QString temp_z3, QString temp_z4)
{
    temp_z1 = zp1;
    temp_z2 = zp2;
    temp_z3 = zp3;
    temp_z4 = zp4;
}

Kod pod przyciskiem na oknie głównym:

Form2 *form2 = new Form2();
        connect(this, SIGNAL(dane(z1, z2, z3, z4)), form2,
                SLOT(odczytDanych(z1, z2, z3, z4)));
        form2->show();

Zarówno funkcja dane jak i odczytDanych jest deklarowana jako publiczny slot, a zmienne które chce przekazać to z1,z2,z3,z4 - w taki sposób aby można było uzyć ich wartości w oknie Form2, zaś zmienne pomocnicze jak z1-4 i zp1-4 są zadeklarowane jako publiczne w plikach nagłówkowych swoich okien.

Mimo to program się kompiluje ale wartości zmiennych zp1-4 są nieprawidłowe, czyli tak jak gdyby połączenie sygnału i slotu w ogóle nie działało, i dane nie zostały przekazane.

0

Nie, nie załapałeś. Funkcja connect() zestawia sygnał ze slotem, przekazujesz tam tylko sygnatury. Chcąc wysłać sygnał musisz uzyć słówka kluczowego emit. Czyli np:

connect(sender,SIGNAL(data(QString,double,int)),receiver,SLOT(odczytDanych(QString,double,int)));

A potem w handlerze:

void OnSomeEvent()
{
     QString str = GetString();
     double dbl = GetDouble();
     int in = GetInt();
     emit dane(str,dbl,in);
}

Poza tym sygnał nie ma implementacji. W nagłówku w klasie tworzysz sobie coś takiego:

signals:
  void dane(QString,double,int);

I to tyle.

0

ok, chyba to zaczynam rozumieć. powiedz mi tylko czy chodzi ci o handler okna głównego czy okna do którego chce przekazać dane?

1

several użył w przykładowej funkcji

void OnSomeEvent()
{
     QString str = getString();
     double dbl = getDouble();
     int in = getInt();
     emit dane(str,dbl,in);
}

słowa kluczowego / makra emit czyli ta funkcja należy do klasy Z której chcesz przesłać ( wyemitować ) dane do jakiejś innej klasy np MainWindow

Jeszcze jeden przykład

class Form
{   
    Q_OBJECT
public:    
    void data();
    
private:
    //...
    
signals:
    void send( QString, int, double );
};

void Form::data()
{
    // tutaj pobierasz sobie dane z formy
    
    QString str = getString();
    int i1 = getInt();
    double d1 = getDouble();
    
    // i wysylasz je emitujac sygnal z klasy
    
    emit( str, i1, d1 );
}


class MainWindow
{    
    Q_OBJECT
public:    
    //...
private:
    //...
    
public slots:
    void receiver( QString, int, double );
    
};

i teraz łączysz sygnał z klasy Form ze slotem w klasie MainWindow jak już wcześniej pokazałem to ja i several ;)

0

rzecz w tym że chce wyemitować sygnał z czterema Stringami Z MainWindow DO Form2 (które jest generwane przyciskiem z MainWindow). Prosze was o łopatologiczne podejście i wytłumaczenie mi tego, bo im głębiej drażę ten temat tym bardziej wydaje mi się że juz nic nie wiem :( Moze pokaże jak to w tej chwili wygląda:

Plik MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QString z1;
    QString z2;
    QString z3;
    QString z4;
    
private slots:
    void on_pushButtonPorownaj_clicked();

signals:
    void dane(QString, QString, QString, QString);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

Plik MainWindow.cpp

 
#include "mainwindow.h"
#include "aboutwindow.h"
#include "summarywindow.h"
#include "documentationwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QFileDialog>
#include <QLineEdit>
#include <QMessageBox>

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

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

void MainWindow::on_pushButtonPorownaj_clicked()
{
        Form2 *f2 = new Form2();
        emit(dane(z1, z2, z3, z4));
        f2->show();
}

Plik Form2.h

 
#ifndef FORM2_H
#define FORM2_H

#include <QDialog>

namespace Ui {
class Form2;
}

class Form2 : public QDialog
{
    Q_OBJECT
    
public:
    explicit Form2(QWidget *parent = 0);
    ~Form2();

    QString zp1;
    QString zp2;
    QString zp3;
    QString zp4;

public slots:
    void odczytDanych();
    
private:
    Ui::Form2 *ui;
};

#endif // FORM2_H

Plik Form2.cpp

#include "mainwindow.h"
#include "form2.h"
#include "ui_form2.h"

#include <QString>

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

    MainWindow *oknoGlowne;
    connect(oknoGlowne, SIGNAL(dane(QString, QString, QString, QString)), this, SLOT(odczytDanych(QString, QString, QString, QString)));
}

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

void Form2::odczytDanych(QString s1, QString n1, QString s2, QString n2)
{
    zp1 = n1;
    zp2 = s1
    zp3 = n2;
    zp4 = s2;
}

Co robie źle?

Chce aby pewne dane z okna głównego były dostępne z poziomu nowego, wygenerowanego okna.

0

Wiem, że już chyba ogarnąłeś, ale tak tylko dla porządku.

emit(dane(z1, z2, z3, z4));

emit to słówko kluczowe, a nie funkcja, więc nie używasz dla niego nawiasów. Używasz jak niżej:

emit dane(z1, z2, z3, z4);

edit
Będąc bardziej ścisłym emit nie jest nawet słówkiem kluczowym, patrz komentarz @MarekR22 do tego posta.

0

Dobra uwaga several ;) to ja jeszcze dodam że jeśli używasz Qt w wersji 5 możesz skorzystać z nowej składni łączenia sygnału ze slotem

connect( Form, &Form::send, MainWindow, &MainWindow::receiver );
0

Ok, sygnał jest już prawidłowo wysyłany, aczkolwiek dalej pozostają problemy ze slotem.

Jak się dowiedziałem sygnał nie potrzebuje implementacji toteż wysyła się go za pomocą emit z nazwą i konkretnymi parametrami, które chce przekazać na nowy Form. Teraz w tym nowym formie, jak rozumiem, należny w konstruktorze połączyć sygnał ze slotem - a slot czyli specyficzny typ metody musi miedć swoją implementacje czy wystarczy jak w składni connect slotu podam zmienne, które chce aby wypełniły się danymi? Czy jednak w składni polecenia connect podaje tylko typy argumentów jakie chce przesłać a podstawiam te wartości do zmiennych w implementacji slotu?

Tak na marginesie, jak już wcześniej wspomniałem w komentarzu, mając Qt w wersji 5 nie jestem w stanie skorzystać z nowej składni connect - kompilator wywala błąd, że nieprawidłowo inicjuje klasę
z której jest wysyłany sygnał (w moim przypadku MainWindow)

connect(MainWindow, &MainWindow::dane, Form2, &Form2::odczytDanych);

Tak oto próbuje połączyć sygnał ze slotem w konstruktorze Form2 i program się kompiluje, jednak Stringi, które chce wypełnić wartościami z MainWindow pozostają puste :/

    MainWindow *oknoGlowne = new MainWindow(this); //jeśli MainWindow nie zadeklaruje przez new to kompilator wywala połączenie z powodu braku sygnału
    connect(oknoGlowne, SIGNAL(dane(QString, QString, QString, QString)),
            this, SLOT(odczytDanych(QString, QString, QString, QString)));
0

a slot czyli specyficzny typ metody musi miedć swoją implementacje czy wystarczy jak w składni connect slotu podam zmienne, które chce aby wypełniły się danymi? Czy jednak w składni polecenia connect podaje tylko typy argumentów jakie chce przesłać a podstawiam te wartości do zmiennych w implementacji slotu?

To drugie. Slot to taki handler eventu, więc ma swoją implementację. Jeśli nic nie zmieniłeś w implementacji z pierwszego postu na tej karcie to powodem może być to:

MainWindow *oknoGlowne;
connect(oknoGlowne, SIGNAL(dane(QString, QString, QString, QString)), this, SLOT(odczytDanych(QString, QString, QString, QString)));

0

Nic nie zmieniałem w implementacji slotu. Emituje sygnał, mam slot którego implementuje i podstawiam mu wartości które ma przejąć od sygnału czyli może rzeczywiście cos jest w doklaracji connect źle? Tylko co? Tworzę wskaźnik do okna głównego z którego sygnał jest wysyłany i generowany jest Form2, by potem (w connect) móc użyć tego wskaźnika i przechwycić sygnał z poziomu Form2. Może coś z tym wskaźnikiem jest nie tak?

Form2 tworzę pod przyciskiem na oknie głównym w taki sposób:

Form2 *f2 = new Form2();
        emit dane(z1, z2, z3, z4);
        f2->show();
1

W klasie MainWindow połącz sygnał który z tej klasy chcesz wysłać ze slotem klasy f2, najlepiej już w konstruktorze
Kolejny prosty przykład jak powinna wyglądać klasa MainWindow

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    // tutaj to najważniejsze...
    f2 = new Form2( this );
    connect( this, SIGNAL(send(QString,QString,QString,QString)), f2, SLOT(receiver(QString,QString,QString,QString)) );
}

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

// umieściłem na formie MainWindow przycisk i ten slot dotyczy właśnie jego
// tutaj pobieram i emituje sygnał z danymi oraz wyświetlam f2
void MainWindow::on_actionForma2_triggered()
{
    QString s1 = ui->lineEdit->text();
    QString s2 = ui->lineEdit_2->text();
    QString s3 = ui->lineEdit_3->text();
    QString s4 = ui->lineEdit_4->text();

    emit send( s1, s2, s3, s4 );
    f2->show();
}

a klasa Form2

#include "form2.h"
#include "ui_form2.h"

Form2::Form2(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Form2)
{
    ui->setupUi(this);
}

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

// ten slot jest wykonywany gdy w MainWindow nacisne buttona
void Form2::receiver( QString n1, QString n2, QString n3, QString n4 )
{
    s1 = n1;
    s2 = n2;
    s3 = n3;
    s4 = n4;

    ui->lineEdit->setText( s1 );
    ui->lineEdit_2->setText( s2 );
    ui->lineEdit_3->setText( s3 );
    ui->lineEdit_4->setText( s4 );
}

Oczywiscie na formie MainWindow i Form2 utworzyłem po 4 lineEdity i MainWindow od razu wpisałem do tych editów przykładowe dane dla testów i dane są przesyłane prawidłowo mam nadzieje że teraz już to zrozumiesz ;)

2

ehhhh @emacs @several,wciskacie panowie kity gościowi...a spodziewałbym się czegoś więcej po swoich uczniach ;P

@sim-ns
W tym wypadku wcale nie potrzebujesz sygnałów i slotów przy założeniu,iż interesujące cię dane nie mogą się zmienić póki odpalony jest dialog.
W takim wypadku definiujesz sobie tej swój Form2 tak:

class Form2 : public QDialog
{
public:
     Form2(type dana1, type dana2, type dana3, type dana4, QWidget *parent=0);
};

Następnie w klasie okna gdzie dialog jest tworzony i pokazywany zapodajesz coś w stylu

void MainWindow::showDialogButtonPressed(void)
{
    Form2 dialog(z1, z2, z3, z4, this);
    if(dialog.exec() == QDialog::Accepted)
    {
         //tutaj co ma się dziać jak użytkownik spowodował stan Accepted dialogu np klikając Ok
    }
}

ot i wsio,a nie jakieś babranie się z sygnałami.

1 użytkowników online, w tym zalogowanych: 0, gości: 1