CDialog

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
Post Reply
George92
Junior
Junior
Posts: 16
Joined: 13 Apr 2013, 00:37
Judet: Dolj

CDialog

Post by George92 » 23 Apr 2013, 20:52

Am o aplicatie in care am mai multe widgeturi derivate din Cdialog cu clase diferite si in widgeturile astia am alte widgeturi cu alte clase. Ideea e ca daca se suprapun 2 dialoguri cand dau click pe cel care se afla in spate as vrea sa apara peste cel din fata nu doar sa primeasca focus, si sa trebuiasca sa il trag cu mousu in lateral. Daca dau click pe marginile dialogului functioneaza , sau am suprascris evenimentu de apasare pt widgeturile dinauntru dialogurilor si functioneaza dar doar pt zona acelor widgeturi nu pt toata suprafata dialogului. Am incercat sa suprascriu si pt el evenimentu acesta dar fara success. Daca dau click pe contur functioneaza dar as vrea sa functioneze pentru toata suprafata dialogului respectiv, am incercat tot felu de metode dar fara success. Nu pot sa arat codu sursa dar orige sugestie este apreciata..



User avatar
bu7ch3r
Membru++
Membru++
Posts: 326
Joined: 17 May 2011, 15:17
Judet: Iaşi
Location: Sofia
Contact:

Re: CDialog

Post by bu7ch3r » 23 Apr 2013, 21:32

Composite pattern. Widgeturile alea tre sa aibe un parinte, pune-l pe parinte sa decida care si cum ia focus.
Din cate imi amintesc poti sa modifici onFocus si sa schimbi z-orderul dialogului/widgetului. "SetWindowPos" cu HWND_TOP :-?? zic si eu ...

In caz ca n-am inteles, poti sa pui niste poze.
Cu stima,
Lupu Claudiu

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 24 Apr 2013, 11:54

Folosesti MFC, nu-i asa?
Daca da, hai sa nu mai folosim termeni imprumutati ("widget", "canvas", alte ninuni de pe alte planete:)) ci cei specifici programarii Windows/MFC, adica "fereastra" ("window") sau "dialog" ("dialog" fiind o clasa particulara de fereastra).
Modul cum se comporta o fereastra fata de cealalta depinde de relatia dintre ele (parent-child sau owner-owned).
De exemplu, daca am doua ferestre A si B iar A este owner-ul lui B, atunci B va sta tot timpul in fata lui A.
Vezi aceste FAQ-uri:
In cazul de fata, asa cum ai formulat problema, se intelege ca ai nevoie de doua dialoguri (unii le zic "dialoage":)) intre care sa nu existe relatie parent-child sau owner-owned.
Mai concret, asta o poti realiza cu doua dialoguri ne-modale (modeless dialogs) intre care sa nu existe relatia de care am vorbit mai sus.
Probabil, in punctul asta nu e destul de clar, insa putem merge mai departe
Trebuie doar sa ne dai mai multe amanunte concrete despre ce si cum ai incercat sa faci.

[ off-topic ]
@bu7ch3r
Claudiu, sunt sigur ca stii si tu, in MFC exista doar 3 pattern-uri mari si late:
  1. Document-view,
  2. KISS, and
  3. last but not the least: good common sense (Windows) programming.
:) ;)

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: CDialog

Post by Marius Bancila » 24 Apr 2013, 15:23

Mai exista inca unul:
4. Don't use MFC containers.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 24 Apr 2013, 15:39

Marius Bancila wrote:Mai exista inca unul:
4. Don't use MFC containers.
O fi. Poti sa-mi explici si mie de ce?

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: CDialog

Post by Marius Bancila » 25 Apr 2013, 10:55

Intrucat containerele STL sunt mai performante (beneficiaza de tot felul de optimizari), pot fi folosite cu o multime de algoritmi (din STL), si beneficiaza de vizualizatori in debugger. As vrea sa vad cum vizualizezi tu elementele unui CPtrArray in fereastra de Watch.

Dar, polemica asta a mai fost dezbatuta de cateva ori, n-are rost s-o luam de la capat. Fiecare sa foloseasca ce-i place mai mult.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 25 Apr 2013, 14:43

Marius Bancila wrote:[...] As vrea sa vad cum vizualizezi tu elementele unui CPtrArray in fereastra de Watch. [...]
Uite-asa
MFC Container Contents in Watch Window.jpg
MFC Container Contents in Watch Window.jpg (35.2 KiB) Viewed 11851 times
Se vede bine? Nu, nu e photoshoped... :)

Cat despre restul: afirmatia "containerele STL sunt mai performante" este falsa atata timp cat am dat mai demult contra-exemple. La fel si pentru "algoritmi" si alte cularai din STL cu care unii incearca sa convinga lumea ca STL + MFC != carcalete si nu te doare capul de asa ceva. ;)

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 25 Apr 2013, 19:28

@Marius: Am pus la sectiunea "FAQ, Tips & Tricks" Cum vizualizez continutul containerelor MFC.

@George92: Te-ai lamurit pana la urma ce trebuie facut cu cele doua ferestre/dialoguri?

George92
Junior
Junior
Posts: 16
Joined: 13 Apr 2013, 00:37
Judet: Dolj

Re: CDialog

Post by George92 » 04 May 2013, 15:43

Am reusit , mersi Ovidiu.
Acum am o alta intrebare, am creat un mic joc in care vreau sa retin scorurile jucatorilor atunci cand jocul se termina sa le scriu intr`un fisier text iar in meniu sa am o optiune High - Scores. As vrea cand se selecteaza acea optiune din meniu sa se incarce din fisierul text scorurile si numele playerului intr`o fereastra sau ceva de genu. Intrebarea mea e cum fac asta in MFC ( nu prea am folosit) , sa folosesc un Cdialog sau s-ar potrivi altceva mai bine?

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 07 May 2013, 12:48

Daca vrei, poti... trebuie doar un pic de transpiratie. :)
Pe scurt si in principiu, iti trebuie:
  1. o structura in care tii date despre un anume jucator: nume, scor, etc;
  2. un array (CArray, CObArray, CTypedPtrArray, etc) in care tii toti jucatorii (structurile de la #1);
  3. poti citi din fisier / scrie in fisier cu CStdioFile sau, mai simplu si mai elegant folosind CArchive;
  4. in fine, un dialog (o clasa derivata din CDialog) in care afisezi, sa zicem primii trei jucatori, in ordinea scorurilor; ii poti obtine sortand descrescator array-ul, dupa scor.
Am zis ca "trebuie un pic de transpiratie", asa ca o sa revin mai acusi cu amanunte si eventual cu o aplicatie demo.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 07 May 2013, 21:27

Deci, cum am promis, iata ceva mai amanuntit.
Am zis ca ti-ar trebui in primul rand o structura care tine datele unui jucator.
Ceva de genul:

Code: Select all

struct CPlayer
{
   CString m_strName;
   UINT m_nScore; 
};
Totusi, hai s-o "complicam" putin!

Code: Select all

class CPlayer : public CObject
{
   DECLARE_SERIAL(CPlayer)

// Attributes
private:
   CString m_strName;
   DWORD m_dwScore;

// Construction
public:
   CPlayer();
   CPlayer(LPCTSTR pszName);
   virtual ~CPlayer();

// Set/Get methods
public:
   void SetName(LPCTSTR pszName);
   const CString& GetName() const;
   void SetScore(DWORD dwScore);
   DWORD GetScore() const;

// Overrides
public:
   virtual void Serialize(CArchive& ar);
};
Am derivat din CObject pentru ca asta ajuta la unele validari, la serializare (scriere/citire in/din arhiva (fisier)), cat si la plasarea lui intr-un aray MFC serializabil.
Implementarea functiei Serialize arata asa:

Code: Select all

void CPlayer::Serialize(CArchive& ar)
{
   CObject::Serialize(ar);

   if(ar.IsStoring())
   {
      // store to archive
      ar << m_strName;
      ar << m_dwScore;
   }
   else
   {
      // load from archive
      ar >> m_strName;
      ar >> m_dwScore;
   }
}
Celelalte metode cred ca-i clar cum se implementeaza. Vei gasi totusi implementarile in proiectul demo pe care il voi atasa la sfarsit.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 07 May 2013, 21:55

In continuare, punem jucatorii intr-un array MFC, sa zicem intr-un CTypedPtrArray.
Ca sa nu incarcam stiu eu ce clasa care are alte treburi cu jdemii de metode care manipuleaza acel array, il punem pe acesta la randul sau intr-o clasa separata, sa-i zicem CPlayersCollection.

Code: Select all

class CPlayersCollection : public CObject
{
   DECLARE_SERIAL(CPlayersCollection)
// Attributes
private:
   CTypedPtrArray<CObArray, CPlayer*> m_arrPlayers;
// Construction
public:
   CPlayersCollection();
   ~CPlayersCollection();
// Operations
public:
   INT_PTR GetPlayersCount() const;
   INT_PTR AddPlayer(CPlayer* pPlayer);
   BOOL SetPlayerScore(LPCTSTR pszName, DWORD dwScore);
   BOOL DeletePlayer(LPCTSTR pszName);
   void DeleteAll();
   BOOL PlayerExists(LPCTSTR pszName) const;
   CPlayer* GetPlayerAt(INT_PTR nIndex) const;
   CPlayer* GetPlayerByName(LPCTSTR pszName) const;
   void SortByScoreDesc();
// Overrides
public:
   virtual void Serialize(CArchive& ar);
// Implementation
private:
   INT_PTR _FindIndexByName(LPCTSTR pszName) const;
   static int _CompareByScoreDesc(const void* left, const void* right);
};
Avem si aici functia Serialize care de data aceasta salveaza/citeste toti jucatorii in/din arhiva si care are implementarea cam asa:

Code: Select all

void CPlayersCollection::Serialize(CArchive& ar)
{
   CObject::Serialize(ar);
   m_arrPlayers.Serialize(ar);
}
Piece of cake, no sweat, like a walking in the park! :)

[off-topic]
@Marius: Iti dau un butoi de bere daca faci mai simplu serializarea cu std::vector si std::fstream. :D
[end off-topic]


Mai dau aici implementarile functiilor pentru sortare, celelalte le gasesti tot in aplicatia demo.

Code: Select all

void CPlayersCollection::SortByScoreDesc()
{
   qsort(m_arrPlayers.GetData(), 
      m_arrPlayers.GetSize(), sizeof(CString*), 
      &CPlayersCollection::_CompareByScoreDesc);
}

Code: Select all

int CPlayersCollection::_CompareByScoreDesc(const void* left, const void* right)
{
   return (*((CPlayer**)right))->GetScore() - (*((CPlayer**)left))->GetScore();
}
Am folosit pentru sortare functia C standard qsort. Puteam la fel de bine sa folosesc std::sort din STL, insa nu m-am legat la cap pentru ca... nu ma doare. :)

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDialog

Post by Ovidiu Cucu » 07 May 2013, 22:38

Ce-a mai ramas?
A mai ramas ce-ai intrebat: cum fac sa afisez "top scores" intr-un dialog.
Pai e simplu. Fac un dialog template in resurse caruia ii adaug controale in care afisez numele si scorurile primilor trei jucatori. Sa zicem ca pun controale edit.
Pe baza acestui dialog template, generez o clasa derivata din CDialog, sa-i zicem CTopScoresDlg.
Pentru asta, iata codul complet:

Code: Select all

// TopScoresDlg.h - CTopScoresDlg class definition
#pragma once

class CPlayersCollection; // forward declaration

class CTopScoresDlg : public CDialog
{
   DECLARE_DYNAMIC(CTopScoresDlg)
// Attributes
private:
   CPlayersCollection& m_players;
   CString m_strName1;
   CString m_strName2;
   CString m_strName3;
   DWORD m_dwScore1;
   DWORD m_dwScore2;
   DWORD m_dwScore3;
// Construction
public:
   CTopScoresDlg(CPlayersCollection& players, CWnd* pParent = NULL);
   virtual ~CTopScoresDlg();
// Dialog Data
   enum {IDD = IDD_TOPSCORES};
// Overrides
protected:
   virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

   DECLARE_MESSAGE_MAP()

};

Code: Select all

// TopScoresDlg.cpp - CTopScoresDlg class implementation
//
#include "stdafx.h"
#include "PlayersDemoApp.h"
#include "TopScoresDlg.h"
#include "Player.h"
#include "PlayersCollection.h"

// CTopScoresDlg dialog

IMPLEMENT_DYNAMIC(CTopScoresDlg, CDialog)

CTopScoresDlg::CTopScoresDlg(CPlayersCollection& players, CWnd* pParent /*=NULL*/)
	: CDialog(CTopScoresDlg::IDD, pParent),
     m_players(players),
     m_dwScore1(0),
     m_dwScore2(0),
     m_dwScore3(0)
{
   // sort by score the players array
   m_players.SortByScoreDesc();

   // fill controls with first 3 players scores (if exist)
   CPlayer* pPlayer = m_players.GetPlayerAt(0);
   if(NULL != pPlayer)
   {
      m_strName1 = pPlayer->GetName();
      m_dwScore1 = pPlayer->GetScore();
   }

   pPlayer = m_players.GetPlayerAt(1);
   if(NULL != pPlayer)
   {
      m_strName2 = pPlayer->GetName();
      m_dwScore2 = pPlayer->GetScore();
   }

   pPlayer = m_players.GetPlayerAt(2);
   if(NULL != pPlayer)
   {
      m_strName3 = pPlayer->GetName();
      m_dwScore3 = pPlayer->GetScore();
   }
}

CTopScoresDlg::~CTopScoresDlg()
{
}

void CTopScoresDlg::DoDataExchange(CDataExchange* pDX)
{
   CDialog::DoDataExchange(pDX);

   DDX_Text(pDX, IDC_EDIT_NAME1, m_strName1);
   DDX_Text(pDX, IDC_EDIT_NAME2, m_strName2);
   DDX_Text(pDX, IDC_EDIT_NAME3, m_strName3);
   DDX_Text(pDX, IDC_EDIT_SCORE1, m_dwScore1);
   DDX_Text(pDX, IDC_EDIT_SCORE2, m_dwScore2);
   DDX_Text(pDX, IDC_EDIT_SCORE3, m_dwScore3);
}

BEGIN_MESSAGE_MAP(CTopScoresDlg, CDialog)
END_MESSAGE_MAP()

// CTopScoresDlg message handlers

Am folosit wizard-ul pentru a adauga variabilele m_strName1... m_dwScore3, cu functiile de dialog data exchange (DDX_Text) corespunzatoare.
Membrul m_players de tipul CPlayersCollection il transmit prin referinta in constructor, unde il sortez in ordinea descrescatoare a scorului, apoi umplu controalele cu nume si scoruri pentru primii trei jucatori.

Aplicatia demo este o aplicatie simpla dialog-based, care contine un obiect CPlayersCollection si un meniu cu handlerele corespunzatoare pentru afisare top scores, salvare/citire in/din fisier, adaugare, modificare si stergere jucatori.
Pentru citire din fisier:

Code: Select all

void CPlayersDemoDlg::OnFileLoadplayers()
{
   TRY
   {
      CString strFileName = _BuildPlayersArchiveFileName();
      CFile file(strFileName, CFile::modeRead);
      CArchive ar(&file, CArchive::load);
      m_players.Serialize(ar);
      _FillPlayersList();
   }
   CATCH_ALL(e)
   {
      e->ReportError();
   }
   END_CATCH_ALL
}

Pentru salvare in fisier:

Code: Select all

void CPlayersDemoDlg::OnFileStoreplayers()
{
   TRY
   {
      CString strFileName = _BuildPlayersArchiveFileName();
      CFile file(strFileName, CFile::modeCreate|CFile::modeWrite);
      CArchive ar(&file, CArchive::store);
      m_players.Serialize(ar);
   }
   CATCH_ALL(e)
   {
      e->ReportError();
   }
   END_CATCH_ALL
}
Pentru afisare top scores intr-un dialog:

Code: Select all

void CPlayersDemoDlg::OnScoreTopscores()
{
   CTopScoresDlg dlg(m_players, this);
   dlg.DoModal();
}
Pentru amanunte si alte briz-brizuri, vezi aplicatia demo:
Demo_Players.zip
(49.52 KiB) Downloaded 408 times
Pentru orice nelamuriri te rog nu ezita sa intrebi.

George92
Junior
Junior
Posts: 16
Joined: 13 Apr 2013, 00:37
Judet: Dolj

Re: CDialog

Post by George92 » 08 May 2013, 23:06

Wow , mersi mult, o sa incerc sa updatez codul pentru aplicatia mea daca o sa mai am probleme o sa te mai intreb dar la prima vedere pare ca e explicat destul de clar. Thanks!

Post Reply