Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

GUI + baza danych- jak to połączyć?

Ostatnio zmodyfikowano 2010-11-23 18:51
Autor Wiadomość
malan
Temat założony przez niniejszego użytkownika
GUI + baza danych- jak to połączyć?
» 2010-11-22 20:35:56
Witam.
Przejdę od razu do rzeczy. Napisałem GUI do programu z użyciem wxWidgets. Stworzyłem klasę okna, w której mam kontroli, menu itp. Wygląda ona mniej więcej tak:
C/C++
class mainWindow
    : public wxFrame
{
public:
    mainWindow( const wxString & title );
    //~mainWindow();
    void onQuit( wxCommandEvent & WXUNUSED( event ) );
    bool performControls();
    bool performMenuBar();
private:
    wxButton * bAddAddress;
    wxComboBox * cbCategories;
    wxMenu * mFile;
    wxMenu * mAddress;
    //...
};

Jak polecił mi (bodajże) kiedyś Pan Piotr, napisałem również klasę myWindow.
C/C++
class myWindow
{
public:
    myWindow();
    ~myWindow();
    bool run();
private:
    mainWindow * application;
};
W tej klasie prócz GUI (czyli obiektu typu mainWindow) chcę umieścić obiekt klasy datebase, która zajmuje się danymi.
Dlaczego tak? Głowna klasa okna, czyli mainWindow z danymi nie ma nic wspólnego. Stworzyłem więc osobną klasę, która łączy jakby te dwa problemy (GUI i dane).

Przedstawię schematycznie, jak wygląda klasa database.
C/C++
class dataA
{
public:
    void setFoo( int newFoo );
private:
    int foo;
};

class dataB
{
public:
    void setSex( int newSex );
private:
    int sex;
};

class database
{
public:
    ...
private:
    std::vector < dataA > A;
    std::vector < dataB > B;
};
Nie wiem, czy może już ktoś widzi jaki mam problem? :)

Dla tych, który się nie domyślają:
W klasie myWindow utworzę obiekt klasy database. Następnie zainicjuję go i prześlę (jak argument) do klasy okna. Będzie to wyglądało mniej więcej tak:
C/C++
database * myBase = new database;
myBase->readA();
myBase->readB();

myWindow * application = new myWindow( & myBase );
application->run(); //Inicjalizacja kontrolek itp.
Nareszcie. Problem polega na tym, że nie chcę mieć publicznych pól w klasie database, a co za tym idzie? W klasie myWindow nie będę mógł dobrać się do (std::vector) dateA oraz dateB. Przykładowo:
C/C++
bool myWindow::run()
{
    // base - obiekt klasy `database`.
    base->dateA[ 0 ].setFoo( 69 ); //Error!
    base->dateB[ 7 ].setSex( 777 ); // Error!
}

Tu moje pytanie: Jak poprawnie i zgodnie ze standardem rozwiązać ten problem?.

Myślałem o tym, aby w zrobić "metody na metody", czyli napisać (w klasie database) metodę, która wywoływałaby metodę (czyżbym nadużywał jakiegoś słowa? ;p) klasy dateA lub dateB. Jednak to rozwiązanie mnie nie zadowala... W sumie musiałbym mieć około 16 metod. A co jeżeli był rozszerzył program do pięciu klas? 60 "metod na metody"?
Dziedziczenie też odpada.
Liczę na Was :).
P-24355
F90M
» 2010-11-22 22:49:52
Możliwe że źle zrozumiałem Twój problem, ale czy przypadkiem klasa zaprzyjaźniona nie rozwiązałaby problemu?
P-24369
malan
Temat założony przez niniejszego użytkownika
» 2010-11-22 23:47:15
Nie rozwiązuje ;p. Wątpię żeby klasa GUI chciała się zaprzyjaźnić z klasą od baz danych ;p.
BTW: ktoś podrzucił mi dość ciekawy pomysł i narodziło się takie maleństwo:
C/C++
#include <iostream>
#include <vector>

class A
{
public:
    A( int newA )
        : aValue( newA )
    {
    }
   
    int get()
    {
        return aValue;
    }
   
    void setA( int newA )
    {
        aValue = newA;
    }
private:
    int aValue;
};

class B
{
public:
    B( int newB )
        : bValue( newB )
    {
    }
   
    int get()
    {
        return bValue;
    }
   
    void setB( int newB )
    {
        bValue = newB;
    }
private:
    int bValue;
};

class C
{
public:
    //Wszystko fajnie, tylko jak się dobiorę z zewnątrz do `aVector` i `bVector`? :)
    //template< typename T >
    //T* getPointer(std::vector<T>& vec, int index)
    //{
    //return ( vec.empty() || index >= vec.size() ) ? 0 : &(vec[index]);
    //}
   
    A * getPointerToAClass( int index )
    {
        return( aVector.empty() || index >= aVector.size() ) ? 0
            : &( aVector[ index ] );
    }
   
    B * getPointerToBClass( int index )
    {
        return( bVector.empty() || index >= bVector.size() ) ? 0
            : &( bVector[ index ] );
    }
   
    void performA()
    {
        for( std::size_t i = 0; i < 5; i++ )
             aVector.push_back( A( i ) );
       
    }
   
    void performB()
    {
        for( std::size_t i = 5; i < 10; i++ )
             bVector.push_back( B( i ) );
       
    }
   
    void printAll()
    {
        std::cout << "A\n";
        for( std::size_t i = 0; i < aVector.size(); i++ )
             std::cout << "#" << i << " " << aVector[ i ].get() << std::endl;
       
        std::cout << "B\n";
        for( std::size_t i = 0; i < bVector.size(); i++ )
             std::cout << "#" << i << " " << bVector[ i ].get() << std::endl;
       
    }
   
    void read()
    {
        performA();
        performB();
    }
   
private:
    std::vector < A > aVector;
    std::vector < B > bVector;
};

class WINDOW
{
public:
    WINDOW()
        : mainClass( new C )
    {
    }
    ~WINDOW()
    {
        delete mainClass;
    }
    void doSomethingImportant()
    {
        A * someObjectA = mainClass->getPointerToAClass( 1 );
        someObjectA->setA( 69 );
       
        B * someObjectB = mainClass->getPointerToBClass( 1 );
        someObjectB->setB( 777 );
    }
   
    void run()
    {
        mainClass->read();
        doSomethingImportant();
        mainClass->printAll();
    }
private:
    C * mainClass;
};

int main()
{
    WINDOW * iLikeCpp0xDotPl = new WINDOW;
    iLikeCpp0xDotPl->run();
    delete iLikeCpp0xDotPl;
    return 0;
}
Rozwiązuje to w zasadzie mój problem, ale może ktoś będzie miał jeszcze jakiś pomysł, więc temat aktualny :).
P-24371
DejaVu
» 2010-11-23 00:11:02
C/C++
class CBla
{
public:
    typedef std::vector < int > DaneT;
    DaneT & dane();
private:
    DaneT m_vDane;
};

CBla::DaneT & CBla::dane()
{
    return m_vDane;
}

//...
CBla obiekt;
obiekt.dane().push_back( 213 );
P-24374
waxx
» 2010-11-23 06:35:31
wrzuc do public
zrob to jako singleton
problem solved


P-24376
malan
Temat założony przez niniejszego użytkownika
» 2010-11-23 17:30:23
@DejaVu: Pańskie rozwiązanie działa, ale:
C/C++
CBla obiekt;
obiekt.dane().push_back( 213 );
std::cout << obiekt.dane()[ 0 ];
Jest ono podobne do mojego, z tym, że Pan zwraca cały std::vector, a ja tylko jeden obiekt :). Aczkolwiek dziękuję :).

@waxx: Public odpada. Nie pisałbym na forum przecież, gdybym chciał wrzucić to do public ;p. Singleton na razie nie jest dla mnie ;p.
P-24390
waxx
» 2010-11-23 18:50:37
Tylko czemu? Dane powinny być dostępne dla całego programu, w tym wypadku singleton będzie najlepszy. Po co się bawić w takie coś?
P-24398
DejaVu
» 2010-11-23 18:51:51
Jeżeli chcesz mieć wektor tylko do odczytu to:
C/C++
class CBla
{
public:
    typedef std::vector < int > DaneT;
    const DaneT & dane() const;
private:
    DaneT m_vDane;
};

const CBla::DaneT & CBla::dane() const
{
    return m_vDane;
}
P-24399
« 1 »
  Strona 1 z 1