Автор Тема: Обръщане към обект в ui от друг клас в Qt4  (Прочетена 1740 пъти)

LinuxFanUNIX

  • Напреднали
  • *****
  • Публикации: 408
  • Distribution: Slackware 12.2
  • Window Manager: KDE 3.5.10
    • Профил
Имам следната структура на проекта:

mainwindow.cpp
mainwindow.h
mainwindow.ui
settings.cpp
settings.h
settings.ui


В MainWindow.UI има поле от типа QLineEdit с име firstName.

В Settings.CPP имам следния код:
Код
GeSHi (C++):
  1. #include "mainwindow.h"
  2. ...
  3. MainWindow *appWin = new MainWindow;
  4. appWin->ui->firstName->setText("SET FIRST NAME!");

В mainwindow.h предварително Ui съм го задал да е public:

Код
GeSHi (C++):
  1. public:
  2.     Ui::MainWindow *ui;

И при тази ситуация от settings.cpp не мога да "заложа" име в QLineEdit който се намира в MainWindow като ui->fisrtName

Та - къде бъркам?

EDIT: Забравих да спомена, че в settings.cpp са include-нати както mainwindow.h, така и ui_mainwindow.h!

Благодаря предварително!
« Последна редакция: Oct 17, 2010, 02:59 от LinuxFanUNIX »
Активен

task_struct

  • Напреднали
  • *****
  • Публикации: 576
  • Distribution: Kubuntu 14.04
  • Window Manager: KDE 4.13
    • Профил
Нещо не мога да си го представя, но това не е правилно от архитектурна гледна точка и от концепцията на Ui. По-правилно за реализация би било, класа MainWindow да има медоти за достъп, през които Settings да може да задава стойности на неговите член данни. Същото важи и за другият клас. Като цяло целта на ООП е да се капсулират данните и ти да ги достъпваш само чрез методи на класа.
Активен

"Minds are like parachutes. They only function when they are open." - James Dewar

irc.freenode.net  / #linux-bg

nifelheim

  • Напреднали
  • *****
  • Публикации: 328
  • Distribution: Kubuntu
  • Window Manager: KDE
    • Профил
    • WWW
Грррр, ако съм разбрал какво искаш да направиш така няма да стане.
Имаш един клас MainWindow, който ти е основният прозорец и един диалог за настройки Settings.
И проблемът ти е как да предаваш разни неща от Settings на MainWindow.
Нормалният начин това да стане в Qt е със signal/slot механизма.

Другият по-тъп начин е да използваш конструктора на Settings диалога,
за да му предадеш като parent указател към MainWindow като:
Код:
class Settings : public QDialog, public Ui_Settings
{
   Q_OBJECT
   public:
      Settings(QWidget *parent = 0);
   private:
      MainWindow *m_Parent;
};

И този диалог да го създадеш в MainWindow, например в слота за натиснат бутон Settings:
...
Код:
Settings dialog(this);
...

После вътре в самия Settings диалог ще можеш да достигаш MainWindow widgets:
Код:
Settings::Settings(QWidget *parent) : QDialog(parent)
{
  setupUi (this);
  m_Parent = (MainWindow*)parent;
 ....
};
След като имаш m_Parent вече навсякъде в Settings диалога може да го използваш.

Но по-добре виж signal/slot механизма.
« Последна редакция: Oct 09, 2010, 23:02 от nifelheim »
Активен

Оптимистът изучава английски език. Песимистът - китайски. А реалистът - автомат Калашников.

task_struct

  • Напреднали
  • *****
  • Публикации: 576
  • Distribution: Kubuntu 14.04
  • Window Manager: KDE 4.13
    • Профил
@nifelheim, има си готова функция наследена от QObject * QObject::parent(). Може направо тя да се използва. Кастването е препоръчително да се прави с qobject_cast<Type>(), защото така Qt  минава през своята Meta-object система и праверява дали е правилен каста :)
Активен

"Minds are like parachutes. They only function when they are open." - James Dewar

irc.freenode.net  / #linux-bg

LinuxFanUNIX

  • Напреднали
  • *****
  • Публикации: 408
  • Distribution: Slackware 12.2
  • Window Manager: KDE 3.5.10
    • Профил
Нещо не мога да си го представя, но това не е правилно от архитектурна гледна точка и от концепцията на Ui. По-правилно за реализация би било, класа MainWindow да има медоти за достъп, през които Settings да може да задава стойности на неговите член данни. Същото важи и за другият клас. Като цяло целта на ООП е да се капсулират данните и ти да ги достъпваш само чрез методи на класа.
Звучи интересно, но май нещо пак сгафих!

Предполагам даваш такова предложение:

mainwindow.cpp
Код
GeSHi (C++):
  1. void MainWindow::setName(QString name) {
  2.     ui->firstName->setText(name);
  3. }

settings.cpp
Код
GeSHi (C++):
  1. MainWindow *appWin = new MainWindow;
  2. appWin->setName("FIRST NAME");

Ако това предлагаш - не става!  :( Въпроса е че не знам и аз по каква причина не става!
Активен

bvbfan

  • Напреднали
  • *****
  • Публикации: 1056
  • Distribution: KaOS
  • Window Manager: Plasma 5
    • Профил
Не ти казва това... Когато създаваш Settings вероятно с натискането на някъкав бутон, ако дадеш кода никой няма да се чуди какво искаш да направиш... В Settings.h това не е вярно => MainWindow *appWin = new MainWindow; не създавай нов прозорец, а ползвай указател към вече създаденият. Така че
MainWindow::CreateWindowSettings()
{
     Settings *pSettings = new Settings( this );
     try {
          pSettings->show();
     } finally {
          if( pSettings ) delete pSettings;
     }
}   
Settings::Settings( MainWindow *MainInstance )
{
     this->appWin = MainInstance;
}

Settings::SetName( const QString WinName )
{
     this->appWin->setName( WinName );
}
« Последна редакция: Oct 10, 2010, 08:36 от bvbfan »
Активен

nifelheim

  • Напреднали
  • *****
  • Публикации: 328
  • Distribution: Kubuntu
  • Window Manager: KDE
    • Профил
    • WWW
Все още само предполагам какво точно искаш да направиш :)
(1) Най-вероятно MainWindow вече съществува, при това се вижда и ти искаш от Settings диалог да сложиш текст на widget в MainWindow.
(2) Създадеш MainWindow в Settings, но не зная защо би правил подобно нещо.

За (1), тогава кодът:
settings.cpp
Код
GeSHi (C++):
  1. MainWindow *appWin = new MainWindow;
  2. appWin->setName("FIRST NAME");
Ако това предлагаш - не става!  :( Въпроса е че не знам и аз по каква причина не става!
Създава нов обект от тип MainWindow и може да му задаваш каквито искаш стойности на контролите, но онзи обект който се вижда е друг и няма нищо общо с новосъздадения, затова и не става.

Ето един пример, който работи според (1):
http://nifelheim.homeip.net/nifelheim/soft/temp/Test/
« Последна редакция: Oct 10, 2010, 10:41 от nifelheim »
Активен

Оптимистът изучава английски език. Песимистът - китайски. А реалистът - автомат Калашников.

task_struct

  • Напреднали
  • *****
  • Публикации: 576
  • Distribution: Kubuntu 14.04
  • Window Manager: KDE 4.13
    • Профил
Звучи интересно, но май нещо пак сгафих!

Предполагам даваш такова предложение:

mainwindow.cpp
Код
GeSHi (C++):
  1. void MainWindow::setName(QString name) {
  2.     ui->firstName->setText(name);
  3. }

settings.cpp
Код
GeSHi (C++):
  1. MainWindow *appWin = new MainWindow;
  2. appWin->setName("FIRST NAME");

Ако това предлагаш - не става!  :( Въпроса е че не знам и аз по каква причина не става!

Така в Settings.cpp създаваш прозорец, различен от този създал диалога. Този прозорец никога не се показва( не му викаш show() ), за това си и мислиш че не става. Правилно е:

1)

mainwindow.cpp
Код
GeSHi (C++):
  1. void MainWindow::setName(QString name) {
  2.     ui->firstName->setText(name);
  3. }


settings.cpp
Код
GeSHi (C++):
  1. MainWindow *appWin = qobject_cast< MainWindow *>( parent() );
  2. appWin->setName("FIRST NAME");


Със signal/slot няма да се получи, защото MainWindow::setName(QString name) има един параметър, a бутона на диалога има сигнал clicked(), който е без параметър. Също така внимавай как създаваш диалога. Има опасност да създадеш втори event_loop и така signals/slots на прозореца няма да се виждат с тези на диалога.

Активен

"Minds are like parachutes. They only function when they are open." - James Dewar

irc.freenode.net  / #linux-bg

remotex

  • Напреднали
  • *****
  • Публикации: 344
    • Профил
Доколкото разбирам става въпрос за главен прозорец и диалог .. тъй като повечето диалогови прозорци са модални т.е. докато си в тях не можеш да цъкаш по главния джам то по принцип постановката е следната:
(примерът е от kbgoffice )

Код
GeSHi (C++):
  1. void MainWindow::on_action_Configure_triggered(){
  2. Ui::OptionsDialog оdui;
  3. QDialog options(this);
  4. odui.setupUi(&options);
  5.  
  6.    odui.generalLayout->setSpacing(SPACE_IN_DIALOGS);
  7.    odui.toek->setChecked(translateOnEveryKey);
  8. //... etc. preliminary dialog setup
  9.  
  10. if (options.exec() == QDialog::Accepted) {
  11. // Save and apply new values
  12. if (translateOnEveryKey != odui.toek->isChecked()) {
  13. translateOnEveryKey = odui.toek->isChecked();
  14. prop->setValue(OPTION_TRANSLATE_ON_EVERY_KEY, translateOnEveryKey);
  15. //...etc. reading values from dialog and applying in mainwindow
  16. }
  17. //...etc
  18. }
  19.  

т.е. главния прозорец създава диалога, задава му начални ст-ти и го показва; при затваряне изчита обратно ст-те и ако има промени си обновява интерфейса и т.н.
Ако не е модален прозореца вече така не става т.е. пак става но няма да отразява динамично промените а ще ги взема само като начални стойности.
Ако е модален но има бутон Apply/Прилагане също не става по този начин.
Обясни по-подробно какъв точно ти е диалога...
« Последна редакция: Oct 11, 2010, 09:20 от remotex »
Активен

nifelheim

  • Напреднали
  • *****
  • Публикации: 328
  • Distribution: Kubuntu
  • Window Manager: KDE
    • Профил
    • WWW
Според ман най-добре си е със SIGNAL/SLOT.
В mainwindow.h да се съзададе една структура за настройките:
Код:
typedef struct
{
   QString firstName;
   // ...
} SETTINGS_t;

и в класа MainWindow се дефинира слот, например:
Код:
   private slots:
      void acceptSettings(SETTINGS_t &settings);

а в класа Settings се дефинира сигнал:
Код:
signals:
   void settingsChanged(SETTINGS_t &settings);

В settings.cpp при натиксане ОК бутона на диалога:
Код:
void Settings::on_btnOK_clicked()
{
  SETTINGS_t settings;

  settings.firstName = editFirstName->text();
  emit settingsChanged(settings);

  accept();
}

В mainwindow.cpp диалога се създава например така:
Код:
void MainWindow::on_btnSettings_clicked()
{
   Settings *dialog = new Settings(this);
   connect( dialog, SIGNAL(settingsChanged(SETTINGS_t&)), this, SLOT(acceptSettings(SETTINGS_t&)) );
   dialog->exec();
   delete dialog;
}
а слота:
Код:
void MainWindow::acceptSettings(SETTINGS_t &settings)
{
   ui->firstName->setText(settings.firstName);
}

Ето тук пример:
http://nifelheim.homeip.net/nifelheim/soft/temp/Test2/
Активен

Оптимистът изучава английски език. Песимистът - китайски. А реалистът - автомат Калашников.

bvbfan

  • Напреднали
  • *****
  • Публикации: 1056
  • Distribution: KaOS
  • Window Manager: Plasma 5
    • Профил
Re: Обръщане към обект в ui от друг клас в Qt4
« Отговор #10 -: Oct 11, 2010, 12:04 »
Аз искам само да отбележа, че когато се пише GUI на QT С++ е желателно да се обработват изключенията, да се затварят прозорци без да се разбере какво се случва :) В много случаи няма нужда нищо по-специално да се прави и try {} finally{} е напълно достатъчно, ама поне няма да хвърчат изключения наляво-надясно. Това си е до навик и според мен само за добро  [_]3
Активен

LinuxFanUNIX

  • Напреднали
  • *****
  • Публикации: 408
  • Distribution: Slackware 12.2
  • Window Manager: KDE 3.5.10
    • Профил
Re: Обръщане към обект в ui от друг клас в Qt4
« Отговор #11 -: Oct 16, 2010, 17:13 »
Код
GeSHi (C++):
  1. MainWindow *appWin = qobject_cast< MainWindow *>( parent() );
  2. appWin->setName("FIRST NAME");

По тоя начин не стана! При изпълнението на setName - програмата се затваря с изходен код: -1073741819л.

Тъй като ми се вижда този начин по-лесен - ако можете - помогнете. Ако не - ще видя другите (по-трудните) варианти.

Благодаря ви за помощта! Очаквам вашите отговори! :)
Активен

nifelheim

  • Напреднали
  • *****
  • Публикации: 328
  • Distribution: Kubuntu
  • Window Manager: KDE
    • Профил
    • WWW
Re: Обръщане към обект в ui от друг клас в Qt4
« Отговор #12 -: Oct 16, 2010, 18:29 »
Вероятно когато си създал диалога не си указал кой е неговият parent.
Settings dialog(this);
И тък като parent се инициализира с NULL: appWin->setName("FIRST NAME") гърми.

http://nifelheim.homeip.net/nifelheim/soft/temp/Test/
« Последна редакция: Oct 16, 2010, 23:03 от neter »
Активен

Оптимистът изучава английски език. Песимистът - китайски. А реалистът - автомат Калашников.

LinuxFanUNIX

  • Напреднали
  • *****
  • Публикации: 408
  • Distribution: Slackware 12.2
  • Window Manager: KDE 3.5.10
    • Профил
Re: Обръщане към обект в ui от друг клас в Qt4
« Отговор #13 -: Oct 17, 2010, 02:59 »
Вероятно когато си създал диалога не си указал кой е неговият parent.
Settings dialog(this);
И тък като parent се инициализира с NULL: appWin->setName("FIRST NAME") гърми.

http://nifelheim.homeip.net/nifelheim/soft/temp/Test/
Прав беше! Така стана!

Благодаря на всички отзовали се! Както всеки път, така и сега ми помогнахте в беда! Благодаря още веднъж!  [_]3 [_]3 [_]3
Активен