Après windows pour les nuls, voici PB pour les bons (ou presque).

Le forum (ô combien francophone) des utilisateurs de Powerbuilder.

Recherche rapide

Annonce

Certaines rubriques, dont des cours, sont uniquement visibles par les membres du forum ^^.
Dans la rubrique Liens & Références, vous avez accès à un sommaire de téléchargement, profitez-en !
Il existe maintenant un nouveau TOPIC "Votre CV en Ligne" accessible uniquement par demande.

#1 29-04-2014 13:26:59

xlat  
0xc0000005
Award: bf
Lieu: Tanger (طنج)
Date d'inscription: 04-12-2010
Messages: 720
Pépites: 11,343
Banque: 100,221,387,868,884,300
Site web

[RESOLU] Controle TreeList

hello,

Est-ce que quelqu'un aurait connaissance d'un wrapper du treelist de rasdlg.dll pour powerbuilder (classic), ou un équivalent ?

Initialement je pensais utiliser un treedatawindow, mais ça ne me permet pas d'avoir des niveaux variables de groupes, et l'utilisation du treeview ne me permet pas d'avoir plusieurs colonnes en même temps.

Dernière modification par seki (10-06-2014 15:07:10)


https://lut.im/eJINqa9o/vAtyxD0h "Don't believe everything you read on the Internet"
    -- Abraham Lincoln

www.ngs.ma

Hors ligne

 

#2 29-04-2014 14:08:36

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: [RESOLU] Controle TreeList

L'idée, c'est de faire ça dans un visual external object :

http://i.imgur.com/vyv3GN6.png


The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#3 29-04-2014 15:03:20

_francois_  
Bienfaiteur du site
Lieu: TOULOUSE
Date d'inscription: 25-03-2010
Messages: 151
Pépites: 178,983,268,111
Banque: 9,223,372,036,854,776,000

Re: [RESOLU] Controle TreeList

Il faut que les colonnes soient redimensionnables ou pas ?
Techniquement en bidouillant un peu on avoir une treeview avec des niveaux différents.
J'avais donné quelques indications un peu à l'arrache dans ce sujet, à voir si c'est applicable à ce qui est souhaité.

Hors ligne

 

#4 30-04-2014 07:40:54

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: [RESOLU] Controle TreeList

On essaie avec Xlat de faire marcher en PB un bout de code C qui donne le résultat de la capture d'écran : une ListView avec un TreeView qui sont déjà associés dans un contrôle de classe TreeList dans la dll rasdlg.dll. Les colonnes sont redimensionnables et le nombre de fils est variable par branche de l'arbre.

Il suffit de quelques lignes de code C (je peux les publier au besoin) pour faire fonctionner l'exemple et on n'arrive pas à faire de même avec une classe visuelle externe (alors que ça fonctionne trivialement pour on contrôle calendrier de comctl32 par exemple)

Au pire on va essayer de wrapper l'ensemble des appels API dans une classe visuelle mais ce serait tellement plus simple de dire à PB d'utiliser la classe de la dll directement...


The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#5 30-04-2014 08:38:06

_francois_  
Bienfaiteur du site
Lieu: TOULOUSE
Date d'inscription: 25-03-2010
Messages: 151
Pépites: 178,983,268,111
Banque: 9,223,372,036,854,776,000

Re: [RESOLU] Controle TreeList

je veux bien voir le code pour ma culture personnelle même si je ne maîtrise pas du tout le sujet.

Hors ligne

 

#6 30-04-2014 09:47:22

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: [RESOLU] Controle TreeList

L'exemple est une appli windows minimale.
Elle définit des messages utilisables avec le contrôle qui semble basé en même temps sur un TreeView et sur un ListView mais qui n'est pas documenté.
Les points remarquables sont :
- l'appel à une fonction FileIconInit() + Shell_GetImageLists() qui permet de charger une ImageList dont les images sont ensuite réutilisées par le TreeList (cette partie est facultative, si on ne veut pas associer d'image aux items, il suffit de ne pas utiliser LVIF_IMAGE dans lvi.mask plus bas dans le code) un truc bizarre c'est que FileIconInit() est appelé directement par son ordinal dans shell32.dll, MSDN explique que c'est ma façon de faire car le prototype de la fonction a été oublié dans les .h de visual c...
- la boucle d'insertion des colonnes par l'envoi du message TLM_INSERTCOLUMN au contrôle
- la boucle d'insertion des items que j'ai placé dans une fonction pour plus facilement insérer des sous niveaux : insertion d'un item dans l'arbre avec TLM_INSERTITEM et le reste des colonnes avec TLM_SETITEM

Je crois que ce qui peut merder avec PB c'est que lors de la création du contrôle avec CreateWindow() on lui passe comme hInstance le handle de rasdlg.dll qu'on a chargé avec LoadLibrary() alors que la plupart du temps quand on crée un contrôle on lui passe le handle de l'application courante... Enfin c'est juste une intuition.

Code: cpp

//https://groups.google.com/d/msg/comp.os.ms-windows.programmer.win32/3Usnxmwo3j4/9j2wFX0PogYJ
// compiler avec 
// cl treetest.cpp /LINK comctl32.lib shell32.lib user32.lib
// avec VC express 2010 le /link pose problème, compiler simplement avec 
// cl treetest.cpp comctl32.lib shell32.lib user32.lib

#define UNICODE
#define _UNICODE

#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
#pragma comment (lib, "comctl32")
#include <shlobj.h> // Shell_GetImageLists

// Based on TreeView & ListView
#define TLM_INSERTITEM     WM_USER + 1
#define TLM_DELETEITEM     WM_USER + 2
#define TLM_DELETEALLITEMS WM_USER + 3
#define TLM_GETITEM        WM_USER + 4
#define TLM_SETITEM        WM_USER + 5
#define TLM_GETITEMCOUNT   WM_USER + 6
#define TLM_GETNEXTITEM    WM_USER + 7
#define TLM_EXPAND         WM_USER + 8
#define TLM_SETIMAGELIST   WM_USER + 9
#define TLM_GETIMAGELIST   WM_USER + 10
#define TLM_INSERTCOLUMN   WM_USER + 11
#define TLM_DELETECOLUMN   WM_USER + 12
#define TLM_SELECTITEM     WM_USER + 13
#define TLM_REDRAWWINDOW   WM_USER + 14
#define TLM_ISEXPANDED     WM_USER + 15
#define TLM_GETCOLUMNWIDTH WM_USER + 16
#define TLM_SETCOLUMNWIDTH WM_USER + 17

typedef struct tagTL_INSERTSTRUCT
{
        PVOID hParent;
        PVOID hInsertAfter;
        LVITEM *plvitem;
} TL_INSERTSTRUCT;

HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void fillItems(HWND list, PVOID hParent, int level, int count, BOOL bNext);


int APIENTRY wWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPWSTR    lpCmdLine,
                     int       nCmdShow) {
        hInst = hInstance;
        WNDCLASSEX wcex = {
                sizeof(WNDCLASSEX), 0, WndProc, 0, 0, hInst, LoadIcon(NULL,IDI_APPLICATION),
                LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("TreeListDemo"), NULL,
        };
        if(!RegisterClassEx(&wcex))
                return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
        //InitCommonControls();
        int nX = (GetSystemMetrics(SM_CXSCREEN) - 860) / 2, nY =(GetSystemMetrics(SM_CYSCREEN) - 600) / 2;
        HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("TestTreeList"),
                WS_OVERLAPPEDWINDOW, nX, nY, 860, 600, NULL, NULL, hInst, NULL);
        if(!hWnd)
                return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
        ShowWindow(hWnd, SW_SHOWNORMAL);
        UpdateWindow(hWnd);
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0)){
                TranslateMessage(&msg);
                DispatchMessage(&msg);
        }
        return (int) msg.wParam;
}

PVOID pInsert;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
        static HWND hWndTL, hWndLV;
        switch (message){
                case WM_CREATE:{
                        BOOL bRet;
                        HIMAGELIST hImageList;
                        HMODULE hLib = LoadLibrary(TEXT("rasdlg.dll"));
                        hWndTL = CreateWindow( TEXT("TreeList"),  TEXT("blah"), WS_VISIBLE |WS_CHILD, 0, 0, 430, 300, hWnd, 0, hLib, NULL );
                        hWndLV = GetWindow(hWndTL, GW_CHILD);



                        // BOOL FileIconInit( _In_  BOOL fRestoreCache );
                        //FileIconInit is not included in a header file. You must call it directly from Shell32.dll, using ordinal 660.
                        typedef BOOL (WINAPI*PFII) (BOOL bRestoreCache);
                        HINSTANCE hInstShell32 = LoadLibrary(TEXT("shell32.dll"));
                        if (hInstShell32){
                                PFII pFII = (PFII)GetProcAddress(hInstShell32, (LPCSTR)MAKEINTRESOURCE(660));
                HRESULT hr;
                if (pFII != NULL)
                  hr = pFII(TRUE);
                                FreeLibrary(hInstShell32);
                        }
                        Shell_GetImageLists(&hImageList, &hImageList);
                        HIMAGELIST hOldIL = (HIMAGELIST)SendMessage(hWndTL,TLM_SETIMAGELIST, 0, (LPARAM)hImageList);

                        //fill the columns
                        LVCOLUMN col={0};
                        col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH ;
                        col.fmt = LVCFMT_LEFT;
                        col.cx = 170;
                        TCHAR sColumnText[20];
                        for (int i = 0; i<5; i++){
                                wsprintf(sColumnText, TEXT("Column %d"), i);
                                col.pszText = sColumnText;
                                i = SendMessage(hWndTL, TLM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&col);
                        }

                        //insert 10 items in the list
                        fillItems(hWndTL, NULL, 0, 10, TRUE);

                        return 0;
                }
                break;
                case WM_SIZE:{
                        MoveWindow(hWndTL, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
                        MoveWindow(hWndLV, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
                        return 0;
                }
                break;
                case WM_DESTROY:{
                        PostQuitMessage(0);
                        return 0;
                }
                break;
                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
}


void fillItems(HWND list, PVOID hParent, int level, int count, BOOL bNext){
        //insert some items in the parent
        BOOL bRet;
        TCHAR sItemText[50];
        TCHAR sLevelText[50];
        PVOID pItem, pSubItem;
        TL_INSERTSTRUCT tlis={0};
        LVITEM lvi={0};
        
        sLevelText[0] = 0;
        for (int i=0; i<level; i++){
                wcscat(sLevelText, TEXT("sub"));
                wcscat(sLevelText, i<count-1?TEXT("-"):TEXT(""));
        }
        
        for (int i = 0; i<count; i++){
                tlis.hInsertAfter = TVI_LAST;
                tlis.hParent = hParent;
                lvi.mask = LVIF_TEXT | LVIF_IMAGE;
                wsprintf(sItemText, TEXT("%sItem %02d - Col 0"), sLevelText, i+1);
                lvi.pszText = sItemText;
                lvi.iImage = i;
                tlis.plvitem = &lvi;
                pItem = (PVOID)SendMessage(list, TLM_INSERTITEM, 0, (LPARAM)&tlis);

                lvi.iItem = (int) pItem;
                for (int j = 1; j<=5; j++){
                        lvi.iSubItem = j;
                        wsprintf(sItemText, TEXT("%sItem %02d - Col %d"), sLevelText, i+1, j);
                        lvi.pszText =sItemText;
                        bRet = SendMessage(list, TLM_SETITEM, 0, (LPARAM)&lvi);
                }

                //inject some children ?
                if(bNext){
                        if(level == 0 && i < 5)
                                fillItems(list, pItem, level+1, 5, i==2 ? TRUE : FALSE);
                        if(level == 1 && i>1 && i<3)
                                fillItems(list, pItem, level+1, 3, FALSE);
                }
        }
}

The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#7 30-04-2014 13:49:15

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: [RESOLU] Controle TreeList

seki a écrit:

Je crois que ce qui peut merder avec PB c'est que lors de la création du contrôle avec CreateWindow() on lui passe comme hInstance le handle de rasdlg.dll qu'on a chargé avec LoadLibrary() alors que la plupart du temps quand on crée un contrôle on lui passe le handle de l'application courante... Enfin c'est juste une intuition.

Je confirme après avoir révisé mes bases de win32 et fait quelques expériences : le problème vient de la déclaration de la classe TreeList dans la dll rasdlg où RegisterClass() n'utilise pas le style CS_GLOBALCLASS. Ce style est nécessaire pourqu'un contrôle soit utilisable à l'extérieur de son module (= de la dll). Sinon il ne sera pas utilisable par une autre application. En gros ce contrôle n'est pas prévu pour être utilisé en dehors de rasdlg.dll, mais le problème est contourné par un hack du code C qui utilise le handle de la dll comme hInstance (un handle d'instance est équivalent à un handle de module). Par contre PB ne sait pas faire ça et n'arrive pas à utiliser ce contrôle non global directement via une classe external visual.


The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#8 10-06-2014 15:04:54

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: [RESOLU] Controle TreeList

Épilogue de l'histoire : comme on ne pouvait pas réutiliser le contrôle MS directement et qu'on avait besoin de pouvoir afficher des données dans un arbre capable d'afficher des colonnes mutiples, et que la datawindow treeview est tout de même assez pourrie (notamment quand on n'a pas le même nombre de niveaux de feuilles dans chaque groupe), et bien on a développé notre propre TreeList

http://github.com/sebkirche/treelist/raw/master/demo_pb.png

Bon, je n'ai pas réinventé la roue, j'ai repris du code existant qui implémente un contrôle Win32 hybride entre un ListView et un TreeView, j'en ai fait une dll et j'ai wrappé un useroject visuel autour

Le code est dispo sur mon GitHub (avec des contributions d'xlat), actuellement pour PB10.5/11.5 et + (version unicode) mais j'essaie de refaire une version ansi pour PB 9. Comme ce n'est pas une extension PBNI, la version non-unicode devrait pouvoir s'utiliser avec des versions précédentes (je sais que certains contributeurs ici se traînent des vieilleries genre PB6... )


The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#9 10-06-2014 15:28:11

_francois_  
Bienfaiteur du site
Lieu: TOULOUSE
Date d'inscription: 25-03-2010
Messages: 151
Pépites: 178,983,268,111
Banque: 9,223,372,036,854,776,000

Re: [RESOLU] Controle TreeList

merci beaucoup

je testerai ça si j'en ai besoin :D
mais là départ pour le nord

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB 1.2.22