Accueil > > > DROPDOWN LISTBOX (WIN32)
DROPDOWN LISTBOX (WIN32)
Information sur la source
Description
Petit exemple d'une solution trouvée suite à cette discussion sur le forum: http://www.cppfrance.com/infomsg/WS_POPUP-F OCUS-0_730993.aspx Le but est de créer une listbox dans une autre fenêtre, sans que le fenêtre mère ne perde le focus, en vue d'avoir le même comportement que les bouton annuler/refaire de Office ou Visual Studio Il y a une fenêtre edit qui permet d'entrer le nombre d'items qui seront présent dans la listbox
Source
- #define _WIN32_WINNT 0x0501
- #define _WIN32_IE 0x0501
- #include <windows.h>
-
- HINSTANCE g_hInst;
- HWND g_hWnd, g_hListbox;
- char g_szAppName[] = "DropDown";
- BOOL g_bCapture = FALSE;
-
- WNDPROC defListboxProc;
-
- #define MAX_ITEMS 10
-
- int __fastcall bnatoi(const char* psz)
- {
- __asm
- {
- xor eax, eax
- push ebx
- xor edx, edx
- xor ebx, ebx
- cmp byte ptr[ecx], '-'
- jne short L1
- inc ecx
- mov edx, 0xFFFFFFFF
- L1:
- mov bl, byte ptr[ecx]
- cmp bl, '0'
- jb short L2
- cmp bl, '9'
- ja short L2
- lea eax, dword ptr[eax + 4 * eax]
- sub bl, '0'
- add eax, eax
- inc ecx
- add eax, ebx
- jmp short L1
- L2:
- add eax, edx
- pop ebx
- xor eax, edx
- }
- }
-
- LRESULT ListBox_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
- {
- POINT pt = {LOWORD(lParam), HIWORD(lParam)};
- RECT clientRect, screenRect;
- POINT screenMousePos;
- GetCursorPos(&screenMousePos);
- GetWindowRect(hWnd, &screenRect);
- GetClientRect(hWnd, &clientRect);
- LRESULT l = 0;
- if(PtInRect(&screenRect, screenMousePos))
- {
- if(pt.x > clientRect.right)
- {
- // Clic dans la fenêtre, mais en dehors de la zone client
- // Donc sur la scollbar
- g_bCapture = TRUE; // Car la ListBox va recevoir WM_CAPTURECHANGED, mais il ne faut pas la fermer
- // On enlève temporairement la capture
- ReleaseCapture();
- l = CallWindowProc((WNDPROC)GetWindowLongPtr(hWnd, GWL_WNDPROC),
- hWnd,
- WM_NCLBUTTONDOWN,
- HTVSCROLL,
- MAKELPARAM(screenMousePos.x, screenMousePos.y));
- SetCapture(hWnd);
- g_bCapture = FALSE;
- }
- return l;
- }
- else DestroyWindow(hWnd); // Clic à coté de la fenêtre
- return 0;
- }
-
- LRESULT ListBox_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
- {
- int sel, count;
- POINT pt;
- RECT rect;
- pt.x = (short)LOWORD(lParam);
- pt.y = (short)HIWORD(lParam);
- GetClientRect(hWnd, &rect);
- if(PtInRect(&rect, pt) || (wParam & MK_LBUTTON))
- {
- // On prend les mouvements de la souris quand on est au dessus de la listBox,
- // ou quand le bouton gauche de la souris est enfoncé
- if(pt.y < 0)
- PostMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0);
- if(pt.y > rect.bottom)
- PostMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0);
- sel = LOWORD(SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam));
- SendMessage(hWnd, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, sel));
- count = (int)SendMessage(hWnd, LB_GETCOUNT, 0, 0);
- if(sel != count - 1)
- SendMessage(hWnd, LB_SELITEMRANGE, FALSE, MAKELPARAM(sel + 1, count - 1));
- }
- return 0;
- }
-
- LRESULT CALLBACK ListboxProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- int sel;
- switch(uMsg)
- {
- case WM_MOUSEMOVE:
- return ListBox_OnMouseMove(hWnd, wParam, lParam);
- case WM_LBUTTONDOWN:
- return ListBox_OnLButtonDown(hWnd, wParam, lParam);
- case WM_KEYDOWN:
- switch(wParam)
- {
- case VK_DOWN:
- sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
- SendMessage(hWnd, LB_SETSEL, 1, sel);
- break;
- case VK_UP:
- sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
- SendMessage(hWnd, LB_SETSEL, 1, sel - 1);
- SendMessage(hWnd, LB_SETSEL, 0, sel - 1);
- break;
- case VK_RETURN:
- goto ok;
- case VK_ESCAPE:
- DestroyWindow(hWnd);
- break;
- }
- break;
- case WM_LBUTTONUP:
- ok:
- case WM_CAPTURECHANGED:
- if(!g_bCapture)
- {
- DestroyWindow(hWnd);
- g_hListbox = 0;
- }
- }
- return CallWindowProc(defListboxProc, hWnd, uMsg, wParam, lParam);
- }
-
- LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- static HWND hEdit;
- switch(uMsg)
- {
- case WM_KEYDOWN:
- case WM_MOUSEWHEEL:
- if(g_hListbox) PostMessage(g_hListbox, uMsg, wParam, lParam);
- break;
- case WM_CREATE:
- hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", 0, WS_VISIBLE | WS_CHILD, 0, 0, 200, 25,
- hWnd, (HMENU)1000, g_hInst, 0);
- CreateWindowEx(0, "Button", "Test", WS_VISIBLE | WS_CHILD, 200, 0, 100, 25,
- hWnd, (HMENU)1001, g_hInst, 0);
- break;
- case WM_COMMAND:
- if(LOWORD(wParam) == 1001)
- {
- char szitems[32];
- GetWindowText(hEdit, szitems, 32);
- int nItems = bnatoi(szitems);
- if(nItems < 1) return 0;
-
- POINT pt = {200, 25}; // Coordonnées dans la fenêtre mère
- // Comme on va mettre le bureau en fenêtre mère, il faut transformer les coordonnées
- MapWindowPoints(hWnd, HWND_DESKTOP, &pt, 1);
- g_hListbox = CreateWindowEx(WS_EX_TOOLWINDOW, "Listbox", 0,
- WS_VSCROLL | WS_BORDER | LBS_HASSTRINGS | LBS_MULTIPLESEL |WS_VISIBLE | WS_CHILD,
- pt.x, pt.y, 100, 100, hWnd, 0, g_hInst, 0);
- int height = (int)SendMessage(g_hListbox, LB_GETITEMHEIGHT, 0, 0);
- if(nItems > MAX_ITEMS) height *= MAX_ITEMS;
- else height *= nItems;
-
- SetWindowPos(g_hListbox, 0, 0, 0, 100, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
- SetParent(g_hListbox, HWND_DESKTOP);
- for(int i = 0; i < nItems; i++)
- SendMessage(g_hListbox, LB_ADDSTRING, 0, (LPARAM)"Chaine d'exemple");
-
- // Donne le focus à la fenêtre principale, pour qu'elle puisse rediriger les
- // message vers la listbox (WM_KEYDOWN, WM_WOUSEWHEEL...)
- SetFocus(hWnd);
- SetCapture(g_hListbox);
- defListboxProc = (WNDPROC)SetWindowLongPtr(g_hListbox, GWL_WNDPROC, (LONG_PTR)ListboxProc);
- }
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
-
- #ifdef _DEBUG
- int main()
- #else
- #pragma comment(linker, "/entry:myWinMain")
- int __stdcall myWinMain()
- #endif
- {
- MSG msg;
- g_hInst = GetModuleHandle(0);
- WNDCLASSEX wcex;
-
- memset(&wcex, 0, sizeof wcex);
- wcex.cbSize = sizeof wcex;
- wcex.lpfnWndProc = AppWndProc;
- wcex.style = CS_HREDRAW | CS_VREDRAW;
- wcex.hInstance = g_hInst;
- wcex.lpszClassName = g_szAppName;
- wcex.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
- wcex.hCursor = LoadCursor(0, IDC_ARROW);
-
- if(!RegisterClassEx(&wcex)) return 1;
-
- g_hWnd = CreateWindowEx(0, g_szAppName, g_szAppName, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, g_hInst, 0);
- if(!g_hWnd) return 1;
-
- ShowWindow(g_hWnd, SW_NORMAL);
- while(GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- #ifdef _DEBUG
- return (int)msg.wParam;
- #else
- ExitProcess(msg.wParam);
- #endif
- }
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0501
#include <windows.h>
HINSTANCE g_hInst;
HWND g_hWnd, g_hListbox;
char g_szAppName[] = "DropDown";
BOOL g_bCapture = FALSE;
WNDPROC defListboxProc;
#define MAX_ITEMS 10
int __fastcall bnatoi(const char* psz)
{
__asm
{
xor eax, eax
push ebx
xor edx, edx
xor ebx, ebx
cmp byte ptr[ecx], '-'
jne short L1
inc ecx
mov edx, 0xFFFFFFFF
L1:
mov bl, byte ptr[ecx]
cmp bl, '0'
jb short L2
cmp bl, '9'
ja short L2
lea eax, dword ptr[eax + 4 * eax]
sub bl, '0'
add eax, eax
inc ecx
add eax, ebx
jmp short L1
L2:
add eax, edx
pop ebx
xor eax, edx
}
}
LRESULT ListBox_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
POINT pt = {LOWORD(lParam), HIWORD(lParam)};
RECT clientRect, screenRect;
POINT screenMousePos;
GetCursorPos(&screenMousePos);
GetWindowRect(hWnd, &screenRect);
GetClientRect(hWnd, &clientRect);
LRESULT l = 0;
if(PtInRect(&screenRect, screenMousePos))
{
if(pt.x > clientRect.right)
{
// Clic dans la fenêtre, mais en dehors de la zone client
// Donc sur la scollbar
g_bCapture = TRUE; // Car la ListBox va recevoir WM_CAPTURECHANGED, mais il ne faut pas la fermer
// On enlève temporairement la capture
ReleaseCapture();
l = CallWindowProc((WNDPROC)GetWindowLongPtr(hWnd, GWL_WNDPROC),
hWnd,
WM_NCLBUTTONDOWN,
HTVSCROLL,
MAKELPARAM(screenMousePos.x, screenMousePos.y));
SetCapture(hWnd);
g_bCapture = FALSE;
}
return l;
}
else DestroyWindow(hWnd); // Clic à coté de la fenêtre
return 0;
}
LRESULT ListBox_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
int sel, count;
POINT pt;
RECT rect;
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
GetClientRect(hWnd, &rect);
if(PtInRect(&rect, pt) || (wParam & MK_LBUTTON))
{
// On prend les mouvements de la souris quand on est au dessus de la listBox,
// ou quand le bouton gauche de la souris est enfoncé
if(pt.y < 0)
PostMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0);
if(pt.y > rect.bottom)
PostMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0);
sel = LOWORD(SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam));
SendMessage(hWnd, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, sel));
count = (int)SendMessage(hWnd, LB_GETCOUNT, 0, 0);
if(sel != count - 1)
SendMessage(hWnd, LB_SELITEMRANGE, FALSE, MAKELPARAM(sel + 1, count - 1));
}
return 0;
}
LRESULT CALLBACK ListboxProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int sel;
switch(uMsg)
{
case WM_MOUSEMOVE:
return ListBox_OnMouseMove(hWnd, wParam, lParam);
case WM_LBUTTONDOWN:
return ListBox_OnLButtonDown(hWnd, wParam, lParam);
case WM_KEYDOWN:
switch(wParam)
{
case VK_DOWN:
sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
SendMessage(hWnd, LB_SETSEL, 1, sel);
break;
case VK_UP:
sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
SendMessage(hWnd, LB_SETSEL, 1, sel - 1);
SendMessage(hWnd, LB_SETSEL, 0, sel - 1);
break;
case VK_RETURN:
goto ok;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
}
break;
case WM_LBUTTONUP:
ok:
case WM_CAPTURECHANGED:
if(!g_bCapture)
{
DestroyWindow(hWnd);
g_hListbox = 0;
}
}
return CallWindowProc(defListboxProc, hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
switch(uMsg)
{
case WM_KEYDOWN:
case WM_MOUSEWHEEL:
if(g_hListbox) PostMessage(g_hListbox, uMsg, wParam, lParam);
break;
case WM_CREATE:
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", 0, WS_VISIBLE | WS_CHILD, 0, 0, 200, 25,
hWnd, (HMENU)1000, g_hInst, 0);
CreateWindowEx(0, "Button", "Test", WS_VISIBLE | WS_CHILD, 200, 0, 100, 25,
hWnd, (HMENU)1001, g_hInst, 0);
break;
case WM_COMMAND:
if(LOWORD(wParam) == 1001)
{
char szitems[32];
GetWindowText(hEdit, szitems, 32);
int nItems = bnatoi(szitems);
if(nItems < 1) return 0;
POINT pt = {200, 25}; // Coordonnées dans la fenêtre mère
// Comme on va mettre le bureau en fenêtre mère, il faut transformer les coordonnées
MapWindowPoints(hWnd, HWND_DESKTOP, &pt, 1);
g_hListbox = CreateWindowEx(WS_EX_TOOLWINDOW, "Listbox", 0,
WS_VSCROLL | WS_BORDER | LBS_HASSTRINGS | LBS_MULTIPLESEL |WS_VISIBLE | WS_CHILD,
pt.x, pt.y, 100, 100, hWnd, 0, g_hInst, 0);
int height = (int)SendMessage(g_hListbox, LB_GETITEMHEIGHT, 0, 0);
if(nItems > MAX_ITEMS) height *= MAX_ITEMS;
else height *= nItems;
SetWindowPos(g_hListbox, 0, 0, 0, 100, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
SetParent(g_hListbox, HWND_DESKTOP);
for(int i = 0; i < nItems; i++)
SendMessage(g_hListbox, LB_ADDSTRING, 0, (LPARAM)"Chaine d'exemple");
// Donne le focus à la fenêtre principale, pour qu'elle puisse rediriger les
// message vers la listbox (WM_KEYDOWN, WM_WOUSEWHEEL...)
SetFocus(hWnd);
SetCapture(g_hListbox);
defListboxProc = (WNDPROC)SetWindowLongPtr(g_hListbox, GWL_WNDPROC, (LONG_PTR)ListboxProc);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#ifdef _DEBUG
int main()
#else
#pragma comment(linker, "/entry:myWinMain")
int __stdcall myWinMain()
#endif
{
MSG msg;
g_hInst = GetModuleHandle(0);
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof wcex);
wcex.cbSize = sizeof wcex;
wcex.lpfnWndProc = AppWndProc;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = g_hInst;
wcex.lpszClassName = g_szAppName;
wcex.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wcex.hCursor = LoadCursor(0, IDC_ARROW);
if(!RegisterClassEx(&wcex)) return 1;
g_hWnd = CreateWindowEx(0, g_szAppName, g_szAppName, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, g_hInst, 0);
if(!g_hWnd) return 1;
ShowWindow(g_hWnd, SW_NORMAL);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef _DEBUG
return (int)msg.wParam;
#else
ExitProcess(msg.wParam);
#endif
}
Historique
- 04 mai 2006 14:48:18 :
- ExitProcess
- 04 mai 2006 14:49:11 :
- Dans l'apercu aussi
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Focus et couleur... en C pour PocketPC [ par fredsor ]
Bonjour a vousDans mon projet, je dois créer différents composant visuel pour Pocket PC : libellé, editbox,bouton et listbox (la aussi pa le choix)- C
WS_POPUP et focus [ par vecchio56 ]
C'est un problème assez compliqué a expliquer... J'ai remarqué que les menus (obtenus par exemple avec TrackPopupMenu) sont des fenêtre popup (avec le
Pb de tableau et de listbox [ par sran_isback ]
Bonjour ! j'ai un ptit probléme concernant un tableau a afficher dans une listbox! j'aimerais bien qu'il m'affiche les nombres de 1 à cents
Gestion dynamique des controles (button, listbox, static text ....etc) [ par SaNcOdeR ]
Bonjour, je recherche une classe de gestion dynamique des controles tel que les bouttons, les check box, les tree ...etc... afin de pouvoir gér&#
ListBox multiline [ par unrealgun ]
Bonjour, Je cherche désespérément comment je peux mettre un texte avec retour a la ligne, donc sur plusieurs lignes dnas un seul item de la listbox ;
transparence + focus + message entre apps [ par alphaone ]
Bonours, 1)Voila je faire un exe qui rend les autre féntre plus ou moin transparente si elle sont selectionner ou non. 2)Et je veux aussi que si on l
focus fenetre [ par darksoul07 ]
existe il une fonction pour connaître la dernière fenêtre (item de menu...) a avoir eu le focus quand je clic sur une autre fenêtre du même programme
imprimer le contenu d'une listBox [ par drcmomo ]
Bonjour tout le monde!!!Je cherche à imprimer des données dans une listBox avec le code ci-dessous quand je lance l'impression il m'imprime une page
Messages au Listbox [Win32] [ par gbourgeois0019 ]
Salut,Je voudrais intercepter le double-click dans un listbox. Je sais qu'il y a des dizaines de posts pour ca mais je les ai tous lus et ca ne marche
Listbox [ par MadMarc ]
Bonjour,j'ai un petit soucis avec une listbox :quand je fais mon SendMessage(Chan->getHwndListeConnectes(),LB_ADDSTRING,0,(LPARAM) buffer); la vale
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|