Montre aussi ton appel.
Version imprimable
Montre aussi ton appel.
Voilà toute ma fonction de tri.
Citation:
void TknoListCtrlEx::Sort ( int nCol, BOOL bAsc )
{
CWaitCursor wc; wc.Restore ( );
TknoListCtrlColEx * pColumn = (TknoListCtrlColEx *) GetColumn ( nCol, FALSE );
ASSERT ( pColumn );
if ( pColumn == NULL )
return;
SortBase::m_nCol = nCol;
SortBase::m_bAsc = bAsc;
switch ( pColumn->GetCompareType ( ) )
{
case TKNOLISTCTRLCOLEX_COMPARE_BYTEXT :
sort ( m_vRows.begin ( ), m_vRows.end ( ), SortByText() );
break;
case TKNOLISTCTRLCOLEX_COMPARE_BYNUMERIC :
sort ( m_vRows.begin ( ), m_vRows.end ( ), SortByNumeric() );
break;
}
SetSortColumn ( nCol, bAsc );
Invalidate ( );
}
C'est encore plus simple:m_nCol et m_bAsc n'ont pas besoin d'être static. Il suffit de les fournir au contructeur:
Avec:Code:
1
2
3
4 sort ( m_vRows.begin ( ), m_vRows.end ( ), SortByText(nCol,bAsc) ); // ou sort ( m_vRows.begin ( ), m_vRows.end ( ), SortByNumeric(nCol,bAsc) );
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 class TknoListCtrlEx : public TknoListCtrl { [...] struct SortBase { public: int m_nCol; BOOL m_bAsc; SortBase(int P_nCol, BOOL P_bAsc): m_nCol(P_nCol),m_bAsc(P_bAsc) {} }; struct SortByText : public SortBase { SortByText(int P_nCol, BOOL P_bAsc):SortBase(P_nCol,P_bAsc) {} [...] }; struct SortByNumeric : public SortBase { SortByNumeric(int P_nCol, BOOL P_bAsc):SortBase(P_nCol,P_bAsc) {} [...] }; }
Voir carrément:
Puis l'implémentation:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 class TknoListCtrlEx : public TknoListCtrl { [...] template<int TypeTri> struct Sort{ public: int m_nCol; BOOL m_bAsc; Sort(int P_nCol, BOOL P_bAsc):m_nCol(P_nCol),m_bAsc(P_bAsc){} bool operator ()(TknoListCtrlRow& rRow1, TknoListCtrlRow& rRow2) }; };
Et enfin, l'utilisation:Code:
1
2
3
4
5
6
7
8
9
10
11
12 template<> bool TknoListCtrlEx::TknoListCtrl<TKNOLISTCTRLCOLEX_COMPARE_BYTEXT>::operator ()(TknoListCtrlRow& rRow1, TknoListCtrlRow& rRow2) { [...] } template<> bool TknoListCtrlEx::TknoListCtrl<TKNOLISTCTRLCOLEX_COMPARE_BYNUMERIC>::operator ()(TknoListCtrlRow& rRow1, TknoListCtrlRow& rRow2) { [...] }
A noter:Code:
1
2
3
4
5
6
7
8
9 switch ( pColumn->GetCompareType ( ) ) { case TKNOLISTCTRLCOLEX_COMPARE_BYTEXT : sort ( m_vRows.begin ( ), m_vRows.end ( ), Sort<TKNOLISTCTRLCOLEX_COMPARE_BYTEXT>(nCol,bAsc) ); break; case TKNOLISTCTRLCOLEX_COMPARE_BYNUMERIC : sort ( m_vRows.begin ( ), m_vRows.end ( ), Sort<TKNOLISTCTRLCOLEX_COMPARE_BYNUMERIC>(nCol,bAsc) ); break; }
1/J'ai mis template<int TypeTri>, mais si c'est un enum tu peux aussi faire template<MonEnum TypeTri>
2/ Lors de l'instanciation de Sort<> tu ne peux lui fournir en paramètre du template le résultat de ta fonction. Ce doit être une constante évaluée à la compilation (à un chouia près, c'est la norme). C'est pourquoi, je maintient le switch. Tu peux, au mieux utiliser un define:
A noter, enfin, que souvent, les normes de qualités imposent un default dans tous les switch/case. Tu peux y ajouter un ASSERT en debug.Code:
1
2
3
4
5
6
7
8
9
10 #define ADD_CASE(IdCase)\ case IdCase:\ sort ( m_vRows.begin ( ), m_vRows.end ( ), Sort<IdCase>(nCol,bAsc) );\ break switch ( pColumn->GetCompareType ( ) ) { ADD_CASE(TKNOLISTCTRLCOLEX_COMPARE_BYTEXT); ADD_CASE(TKNOLISTCTRLCOLEX_COMPARE_BYNUMERIC); }
J'adore ça me parai tellement simple. :yaisse2: Mais il fallait y penser.
Par contre j'ai une dernière question pure MFC.
En fait ma liste n'est utilisable que si elle est définie dans les resources avec LVS_REPORT et LVS_OWNERDATA.
Et ça me gonfle de faire les modifications à chaque fois.
J'aimerai donc modifier les styles de ces futures directement en Report et en OwnerData.
J'ai bien compris que si la liste est créée avec les resources, le "PreCreateWindow" n'est jamais appelé. J'ai testé et je passe dans le "PreSubclassWindow". J'avais cru comprendre que je pouvais faire la modification du style. Mais ça ne fonctionne pas.
J'ai même essayé en mettant le "ModifyStyle" avant et après. Et toujours rien.Citation:
void TknoListCtrlEx::PreCreateWindow ( )
{
ModifyStyle ( LVS_ICON | LVS_LIST, LVS_REPORT | LVS_OWNERDATA );
TknoListCtrl::PreCreateWindow ( );
}
Auriez vous une idée ?
Je ne suis pas sûr que LVS_OWNERDATA puisse se changer dynamiquement, mais normalement LVS_REPORT, si.
Enfin, un rechercher/remplacer va des fois bien plus vite que de chercher une solution un peu complexe.
Je viens de voir ton code optimiser encore plus le code. Ouais c'est impressionnant mais j'avoue que c'est trop pour moi.
Accessoirement je ne vois pas l'utilité de complexifier le code à ce point. Mais je peux me tromper.
Je trouve ça extrême pour les quelques fonctions de tri que j'ai besoin.
Surtout que j'aime bien l'idée d'avoir un héritage comme c'est le cas actuellement.
Ça me permet de réfléchir à une fonction de tri avec les dates.
_____________________________
Effectivement je suis d'accord, j'ai actuellement une fonction de validité pour vérifier que les deux configs sont bien active.
Je crois que je vais finir par laisser ça comme ça.
En tout cas merci à vous tous pour votre aide. Grâce à cette discussion j'ai réussi à faire ce que je voulais mais surtout j'ai beaucoup appris. :merci:
Je reviens vers vous pour une petite question.
J'ai fais mes tests sur une liste de 100 000. C'est top ça marche.
Je viens de l'intégrer et j'ai commencé par une petite liste pour ne pas pousser le bouchon trop loin.
Et je viens de tomber sur un autre truc des stl. En fait pour fait fonctionner le sort, il me fallait un Predicate avec l'operateur "()". Mais là il me manque le ">" et le "<". En chargeant bien j'ai compris qu'en dessous de 32 lignes, le "sort" n'utilise pas le QuickSort mais le "InsertionSort".
Avez vous déjà entendu parler de ça ou pas ?
Ça y est je viens de comprendre exactement ce qu'il se passe et c'est problématique.
Ça vient du fait que plusieurs de mes chaines de caractères sont égales.
Car lors du sort, l'algo utilise le Predicate pour réaliser une fonction "<". Cependant comme les 2 chaines testées sont égales, l'algo me met une erreur.
Voici le code stl qui pose problème :En cherchant un peu, beaucoup, on a trouvé que lorsque les 2 éléments d'un Predicate sont égaux, il faut ABSOLUMENT retourner "false".Code:
1
2
3
4
5
6
7
8
9
10 template<class _Pr, class _Ty1, class _Ty2> inline bool __CLRCALL_OR_CDECL _Debug_lt_pred(_Pr _Pred, _Ty1& _Left, _Ty2& _Right, const wchar_t *_Where, unsigned int _Line) { // test if _Pred(_Left, _Right) and _Pred is strict weak ordering if (!_Pred(_Left, _Right)) return (false); else if (_Pred(_Right, _Left)) _DEBUG_ERROR2("invalid operator<", _Where, _Line); return (true); }
J'ai donc effectué cette vérification supplémentaire et c'est bon ça fonctionne de nouveau.
Effectivement, je n'avais jamais fait attention à la ligne (pourtant en italique) comme quoi l'opérateur de comparaison doit suivre la condition de strict weak ordering. D'ailleurs, on retrouve dans STL Précis&Concis de Ray Lischner, on trouve: la fonction de comparaison doit suivre l'ordre faible strict et en particulier A<A est toujours faux!