migf1 Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Βασικά έχω 2 ερωτήσεις: 1) Είναι όντως τόσο πολύπλοκο να διαχειριστεί κανείς spinboxes (updown control + edit control) στο Win32 API με σκέτη C (χωρίς χρήση του UDS_SETBUDDYINT, γιατί π.χ. θέλω να περιέχει και floats το edit-box, και ως βήμα και ως αποτέλεσμα, αντί για σκέτους int) ; Κατέληξα να φτιάξω δική μου, εσωτερική, απεικόνιση του spin-box η οποία μαζί με τις ας τις πούμε μεθόδους της λειτουργεί ως ενδιάμεσο layer για αποστολή & λήψη πληροφοριών προς και από τα actual controls του Dialog, για να μπορώ να διαχειρίζομαι uniformly τα διάφορα spinboxes του Dialog. > /** * Internal representation of a custom spin control, consisting * of an updown and an edit-box control, with the following mandatory * prerequisites: * - the updown is bonded to the edit-box with the UDS_AUTOBUDDY style * - the updown does NOT have the UDS_SETBUDDYINT style set */ typedef struct TDlgSpin { enum { DLGSPIN_TSTEP_INT = 0, DLGSPIN_TSTEP_FLOAT } udTStep; // type of step int edId; TCHAR edText[ MAXLEN_DLGSPIN_TEXT ]; int udId; int udHi; int udLo; int udPos; union { int Int; float Float;} udStep; int udDelta; } TDlgSpin; /*******************************************************//** * *********************************************************** */ BOOL dlgSpin_set( TDlgSpin *spin, int udTStep, int edId, TCHAR *edText, int udId, int udHi, int udLo, int udPos, float udStep, int udDelta ) { if ( !spin ) return FALSE; spin->udTStep = udTStep; spin->edId = edId; _tcsncpy(spin->edText, edText, MAXLEN_DLGSPIN_TEXT ); spin->edText[ _tcslen(spin->edText) ] = TEXT('\0'); spin->udId = udId; spin->udHi = udHi; spin->udLo = udLo; spin->udPos = udPos; if ( udTStep == DLGSPIN_TSTEP_FLOAT ) spin->udStep.Float = udStep; else spin->udStep.Int = (int)udStep; spin->udDelta = udDelta; return TRUE; } /*******************************************************//** * *********************************************************** */ BOOL dlgSpin_toDlg( const TDlgSpin *spin, HWND hDlg ) { if ( NULL == hDlg || !spin ) return FALSE; SetDlgItemText( hDlg, spin->edId, spin->edText ); SendDlgItemMessage( hDlg, spin->udId, UDM_SETRANGE, (WPARAM)0, MAKELPARAM(spin->udHi, spin->udLo) ); SendDlgItemMessage( hDlg, spin->udId, UDM_SETPOS, (WPARAM)0, MAKELPARAM(spin->udPos, 0) ); return TRUE; } /*******************************************************//** * *********************************************************** */ BOOL DlgUpdateSpin( HWND hDlg, const TDlgSpin *spin ) { TCHAR txt[1024] = { TEXT('\0') }; const int txtsize = sizeof(txt) / sizeof(TCHAR); int ntchars = 0; /* sanity check */ if ( NULL == hDlg || !spin ) return FALSE; // get the text of the edit-box GetDlgItemText( hDlg, spin->edId, txt, txtsize); // convert text to number & apply spin->udStep (according to spin->udDelta) if ( DLGSPIN_TSTEP_FLOAT == spin->udTStep ) { float resFloat = _tstof(txt); if ( spin->udDelta > 0 ) // user pressed up-arrow resFloat += spin->udStep.Float; else if ( spin->udDelta < 0 ) // user pressed down-arrow resFloat -= spin->udStep.Float; // auto-fix result to range-boundaries, if necessary if ( resFloat < (float)(spin->udLo) ) resFloat = (float)(spin->udLo); else if ( resFloat > (float)(spin->udHi) ) resFloat = (float)(spin->udHi); // Convert the (float) result back to text & put it in the edit-box ntchars = my_snprintf(txt, txtsize, TEXT("%.2f"), resFloat); if ( ntchars >= txtsize ) { myINFO_BOX( TEXT("Buffer overrun!") ); return FALSE; } } else { //msgboxf( TEXT("Info"), TEXT("iDelta: %d, udStep.Int: %d"), spin->udDelta, spin->udStep.Int); int resInt = _tstoi(txt); if ( spin->udDelta > 0 ) // user pressed up-arrow resInt += spin->udStep.Int; else if ( spin->udDelta < 0 ) // user pressed down-arrow resInt -= spin->udStep.Int; // auto-fix result to range-boundaries, if necessary if (resInt < spin->udLo ) resInt = spin->udLo; else if (resInt > spin->udHi) resInt = spin->udHi; // Convert the (int) result back to text & put it in the edit-box ntchars = my_snprintf(txt, txtsize, TEXT("%d"), resInt); if ( ntchars >= txtsize ) { myINFO_BOX( TEXT("Buffer overrun!") ); return FALSE; } } SetDlgItemText( hDlg, spin->edId, txt ); return TRUE; } κλπ, κλπ 2) Στην τεκμηρίωση αναφέρει πως τα ud-controls στέλνουν WM_VSCRL ή WM_HSCRL messages, αλλά εγώ τα πιάνω με το WM_NOTIFY που προηγείται, για να πάρω το iDelta και να αυξήσω/μειώσω ανάλογα το κείμενο του buddy... > ... case WM_NOTIFY: switch( ((LPNMHDR)lParam)->code ) { int udId; TDlgSpin spin; case UDN_DELTAPOS: udId = ((LPNMHDR)lParam)->idFrom; if ( UD_TAID == udId ) { memcpy( &spin, &g_tadataDlg.identification.spinTAID, sizeof( TDlgSpin ) ); spin.udDelta = ((LPNMUPDOWN)lParam)->iDelta; //msgboxf( TEXT("Info"), TEXT("iDelta: %d"), spin.udDelta); // DlgUpdateSpin( hDlg, &spin ); } break; ... Με αυτό κάνω τη δουλειά μου, χρειάζεται να ελέγξω και το WM_VSCRL; Αν ναι, γιατί;
παπι Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Φτιαξε μια νεα class η οποια θα ειναι ενα control updown+edit
migf1 Δημοσ. 12 Μαΐου 2012 Μέλος Δημοσ. 12 Μαΐου 2012 Αυτό δεν κάνω μέσα στον κώδικα που έχω παραθέσει στο spoiler του 1ου ποστ;
παπι Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Αυτό δεν κάνω μέσα στον κώδικα που έχω παραθέσει στο spoiler του 1ου ποστ; Οχι
migf1 Δημοσ. 12 Μαΐου 2012 Μέλος Δημοσ. 12 Μαΐου 2012 Οχι Τι όχι; Τι εννοείς όταν λες κλάση; Είδες ότι αναφέρομαι σε C;
παπι Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Τι όχι; Τι εννοείς όταν λες κλάση; Είδες ότι αναφέρομαι σε C; Οπως φτιαχνεις το main window (νεα wndclass/ex registerclass, wndproc etc) ετσι θα φτιαξεις μια κλαση που θα εχει μεσα μονο ενα edit και το updown το οποιο θα επικοινωνει μεσου Get/SendMessage με το main window
migf1 Δημοσ. 12 Μαΐου 2012 Μέλος Δημοσ. 12 Μαΐου 2012 Οπως φτιαχνεις το main window (νεα wndclass/ex registerclass, wndproc etc) ετσι θα φτιαξεις μια κλαση που θα εχει μεσα μονο ενα edit και το updown το οποιο θα επικοινωνει μεσου Get/SendMessage με το main window Ωραίο! Δεν το είχα σκεφτεί. Thanks! Αν και θα πρέπει να ρίξω διάβασμα γιατί δεν θυμάμαι τίποτα. EDIT: Πες μου και για το WM_VSCRL μιας που σε βρήκα εύκαιρο, το χρειάζομαι; Θα με εξυπηρετήσει σε κάτι;
παπι Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Πες μου και για το WM_VSCRL μιας που σε βρήκα εύκαιρο, το χρειάζομαι; Θα με εξυπηρετήσει σε κάτι; Με το msdn δουλευω, δεν τα ξερω ολα απ'εξω. Τεσπα θα φτιαξω ενα τετοιο control για εξασκηση και θα το κανω ποστ
migf1 Δημοσ. 12 Μαΐου 2012 Μέλος Δημοσ. 12 Μαΐου 2012 Με το msdn δουλευω, δεν τα ξερω ολα απ'εξω. Τεσπα θα φτιαξω ενα τετοιο control για εξασκηση και θα το κανω ποστ Όχι ρε συ, δεν χρειάζεται. Θα τα βρω, ήταν πολύ ωραία ιδέα το wndclass. Εννοώ δεν χρειάζεται να ταλαιπωρηθείς εσύ για μένα (άλλο αν θες να το κάνεις κι εσύ για φρεσκάρισμα).
moukoublen Δημοσ. 12 Μαΐου 2012 Δημοσ. 12 Μαΐου 2012 Να κάνω μια άσχετη ερώτηση καθαρά για κουβεντούλα. Γιατί χρησιμοποιείς C γιατί κάτι τέτοιο; Και επίσης. Αυτό το κανεις κάπου επαγγελματικά η χομπυστικά;
migf1 Δημοσ. 12 Μαΐου 2012 Μέλος Δημοσ. 12 Μαΐου 2012 Να κάνω μια άσχετη ερώτηση καθαρά για κουβεντούλα. Γιατί χρησιμοποιείς C γιατί κάτι τέτοιο; Και επίσης. Αυτό το κανεις κάπου επαγγελματικά η χομπυστικά; Χομπίστικα. Χρησιμοποιώ C γιατί θέλω να φρεσκάρω τη μνήμη μου στο pure Win32 API. Για να είμαι απολύτως ειλικρινής, ξεκίνησα γιατί ήθελα να επιβεβαιώσω/διαψεύσω την απόφασή μου πολλά χρόνια πριν να μην ασχοληθώ ποτέ ξανά με Win32 API + C όταν πρωτο-προγραμμάτισα σε GTK+. 1-2 μέρες έχω που άρχισα να ξανασκαλίζω πάλι το Win32 API, και μέχρι στιγμής νομίζω είχα πάρει σωστή απόφαση τότε
migf1 Δημοσ. 13 Μαΐου 2012 Μέλος Δημοσ. 13 Μαΐου 2012 Όχι ρε συ, δεν χρειάζεται. Θα τα βρω, ήταν πολύ ωραία ιδέα το wndclass. Εννοώ δεν χρειάζεται να ταλαιπωρηθείς εσύ για μένα (άλλο αν θες να το κάνεις κι εσύ για φρεσκάρισμα). Τελικά ίσως και να μην είναι και τόσο καλή ιδέα ξεχωριστού wndclass για custom control, εκτός αν φταίει που δεν έχω ακουμπήσει το winapi για χρόνια και η λύση αυτή μου φαίνεται πολύ πιο περίπλοκη από αυτήν που έχω παραθέσει στο 1ο ποστ. Έριξα λίγο διάβασμα σήμερα και η αλήθεια είναι πως περισσότερο χάθηκα, παρά βοηθήθηκα. Εννοώ πως μάλλον μου δημιουργήθηκαν περισσότερες απορίες από τις αρχικές μου. Για παράδειγμα, η wndclass του custom control πρέπει να είναι global ή local? Χρειάζεται να χρησιμοποιήσω InitCommonControls() / InitCommonControlsEx() για αυτό το custom control ή όχι; Σε γενικές γραμμές, για κάθε απορία για την οποία διαβάζω, γεννιόνται άλλες 1-2 που θέλουν κι άλλο διάβασμα, με αποτέλεσμα στο τέλος σχεδόν να έχω ξεχάσει από ποια απορία μου ξεκίνησα να διαβάζω Πέρα από τα παραπάνω, έχω την εντύπωση πως το overhead δημιουργίας callback CustomControlProc() που θα διαχειρίζεται τα events του custom control θα είναι πολύ μεγαλύτερο από αυτό που κάνω στο 1ο ποστ. @παπι: Αν τελικά βρεις χρόνο & κέφι να γράψεις κώδικα δημιουργίας και διαχείρισης ενός custom spinner control, ανέβασέ τον αν θες και στο νήμα, να πάρω ιδέες. Προς το παρόν θα το συνεχίσω με τον τρόπο του 1ου ποστ (μου φαντάζει πολύ απλός τελικά ) Για όποιον ενδιαφέρεται, ξεκίνησα να διαβάζω από αυτές τις 2 σελίδες: 1. http://msdn.microsof...v=vs.85%29.aspx 2. http://msdn.microsof...v=vs.85%29.aspx αλλά διάβασα και μερικές ντουζίνες ακόμα, που περισσότερο με μπέρδεψαν παρά με βοήθησαν. Π.χ. http://stackoverflow...tcommoncontrols http://zetcode.com/t...customcontrols/
παπι Δημοσ. 13 Μαΐου 2012 Δημοσ. 13 Μαΐου 2012 Μπορει να εχει αρκετα bugs αλλα δε βαριεσαι. main.cpp >#include "etc.h" #include "updown_edit.h" PWSTR strs[] = { L"Ενα", L"Δυο", L"Τρια", L"Τεσσερα" }; LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE,PSTR,int) { WNDCLASSEX sex ={ 0 }; HWND hWnd; MSG msg; sex.cbSize = sizeof(sex); sex.hbrBackground = (HBRUSH) COLOR_WINDOW; sex.hInstance = hInst; sex.hCursor = LoadCursor(NULL, IDC_ARROW); sex.lpfnWndProc = WndProc; sex.style = (CS_HREDRAW | CS_VREDRAW); sex.lpszClassName = L"mainCls"; RegisterClassEx(&sex); hWnd = CreateWindow(L"mainCls",L"Main Window",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInst,0); ShowWindow(hWnd,SW_SHOW); while(GetMessage(&msg,0,0,0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HWND hCtrl; UPDOWNEDIT_INITSTRUCT_NUMERIC num; UPDOWNEDIT_INITSTRUCT_STRING_ARRAY str; switch(msg) { case WM_CREATE: InitMyControl(); hCtrl = CreateWindow(UPDOWNEDIT_CLASS,0,WS_VISIBLE | WS_CHILD,100,100,120,27,hWnd,(HMENU)100,0,0); num.flag = UINF_FLOAT; num.f.end = 10.0f; num.f.pos = 7.0f; num.f.start = 5.0f; num.f.factor = 0.1f; UpdownEdit_InitNumeric(hCtrl,&num); // set numeric updown hCtrl = CreateWindow(UPDOWNEDIT_CLASS,0,WS_VISIBLE | WS_CHILD,100,200,120,27,hWnd,(HMENU)101,0,0); str.count = 4; str.pos = 0; str.pStrings = strs; UpdownEdit_InitArray(hCtrl,&str); CreateWindow(UPDOWNEDIT_CLASS,0,WS_VISIBLE | WS_CHILD,100,300,120,27,hWnd,(HMENU)102,0,0); break; case WM_CLOSE: PostQuitMessage(0); break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } updown_edit.h >#pragma once #include "etc.h" #include <stdio.h> #include <tchar.h> #define UPDOWNEDIT_CLASS L"updownedit" //commands #define WMC_VALUE_CHANGE 100 //messages #define UDEM_INIT (WM_USER + 1) #define UINF_FLOAT 1 #define UINF_INTEGER 2 #define UDET_NUMERIC 1 #define UDET_ARRAY 2 typedef struct { int flag; struct { float start; float end; float pos; float factor; }f; struct { int start; int end; int pos; int factor; }i; }UPDOWNEDIT_INITSTRUCT_NUMERIC; typedef struct { PTCHAR *pStrings; int count; int pos; }UPDOWNEDIT_INITSTRUCT_STRING_ARRAY; #define UpdownEdit_InitNumeric(hCtrl,pUin) \ SendMessage(hCtrl,UDEM_INIT,UDET_NUMERIC, (LPARAM)pUin) #define UpdownEdit_InitArray(hCtrl,pUisa) \ SendMessage(hCtrl,UDEM_INIT,UDET_ARRAY,(LPARAM)pUisa) #ifndef __cplusplus void InitMyControl(); #else extern "C" void InitMyControl(); #endif updown_edit.c > #include "updown_edit.h" #define ID_EDIT 100 #define ID_UPDOWN 101 typedef struct { int type; UPDOWNEDIT_INITSTRUCT_NUMERIC numeric; UPDOWNEDIT_INITSTRUCT_STRING_ARRAY strings; }UPDOWNEDIT_INTERNAL_DATA; //internal LRESULT CALLBACK UpDonwProc(HWND hWnd,UINT msg, WPARAM wParam,LPARAM lParam); void OnCreate(HWND hWnd,CREATESTRUCT* pcs); void OnDestroy(HWND hWnd); void changeValue(HWND hWnd,int factor); void InitMyControl() { WNDCLASSEX sex = { 0 }; sex.cbSize = sizeof(sex); sex.lpszClassName = UPDOWNEDIT_CLASS; sex.hCursor = LoadCursor(NULL,IDC_ARROW); sex.lpfnWndProc = UpDonwProc; RegisterClassEx(&sex); } LRESULT CALLBACK UpDonwProc(HWND hWnd,UINT msg, WPARAM wParam,LPARAM lParam) { int factor; UPDOWNEDIT_INTERNAL_DATA *pInternalData; UPDOWNEDIT_INITSTRUCT_STRING_ARRAY *pUisa; UPDOWNEDIT_INITSTRUCT_NUMERIC *pUin; switch(msg) { case UDEM_INIT: pInternalData = (UPDOWNEDIT_INTERNAL_DATA*) GetWindowLong(hWnd,GWLP_USERDATA); switch(wParam) { case UDET_ARRAY: pUisa = (UPDOWNEDIT_INITSTRUCT_STRING_ARRAY*) lParam; pInternalData->strings.count = pUisa->count; pInternalData->strings.pos = pUisa->pos; pInternalData->strings.pStrings = malloc(pUisa->count * sizeof(void*)); for(factor = 0; factor < pUisa->count; factor++) { #if _UNICODE pInternalData->strings.pStrings[factor] = wcsdup(pUisa->pStrings[factor]); #else pInternalData->strings.pStrings[factor] = strdup(pUisa->pStrings[factor]); #endif } pInternalData->type = UDET_ARRAY; changeValue(hWnd,0); break; case UDET_NUMERIC: pUin = (UPDOWNEDIT_INITSTRUCT_NUMERIC*) lParam; memcpy(&pInternalData->numeric,pUin,sizeof(UPDOWNEDIT_INITSTRUCT_NUMERIC)); pInternalData->type = UDET_NUMERIC; changeValue(hWnd,0); break; } break; case WM_CREATE: OnCreate(hWnd,(CREATESTRUCT*)lParam); break; case WM_DESTROY: OnDestroy(hWnd); break; case WM_GETTEXT: GetDlgItemText(hWnd,ID_EDIT,(LPWSTR)lParam,wParam); break; case WM_NOTIFY: switch( ((NMHDR*)lParam)->code) { case UDN_DELTAPOS: if( ((NMUPDOWN*)lParam)->iDelta > 0) factor = -1; else if( ((NMUPDOWN*)lParam)->iDelta < 0) factor = 1; changeValue(hWnd,factor); SendMessage(GetParent(hWnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hWnd),WMC_VALUE_CHANGE),(LPARAM)hWnd); // send wm break; } break; case WM_MOUSEWHEEL: if( (short)HIWORD(wParam) > 0) factor = -1; else if( (short)HIWORD(wParam) < 0) factor = 1; else factor = 0.0; changeValue(hWnd,factor); SendMessage(GetParent(hWnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hWnd),WMC_VALUE_CHANGE),(LPARAM)hWnd); // send wm break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } void OnCreate(HWND hWnd,CREATESTRUCT* pcs) { UPDOWNEDIT_INTERNAL_DATA *pInteralData; CreateWindow(WC_EDIT,L"Unset",WS_CHILD | WS_VISIBLE,0,0,pcs->cx - 30,pcs->cy,hWnd,(HMENU)ID_EDIT,0,0); CreateWindow(UPDOWN_CLASS,0,WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT | UDS_ALIGNRIGHT,pcs->cx - 30,0,30,30,hWnd,(HMENU)ID_UPDOWN,0,0); pInteralData = malloc(sizeof(UPDOWNEDIT_INTERNAL_DATA)); SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG) pInteralData); } void changeValue(HWND hWnd,int factor) { char cBuf[120]; float fTmp; int iTmp; UPDOWNEDIT_INTERNAL_DATA *pInteralData; pInteralData = (UPDOWNEDIT_INTERNAL_DATA*) GetWindowLongPtr(hWnd,GWLP_USERDATA); if(pInteralData->type == UDET_NUMERIC) { if( pInteralData->numeric.flag == UINF_FLOAT ) { fTmp = pInteralData->numeric.f.pos + (pInteralData->numeric.f.factor * (float)factor); if(fTmp > pInteralData->numeric.f.end ||fTmp < pInteralData->numeric.f.start) return; pInteralData->numeric.f.pos = fTmp; sprintf(cBuf,"%f",fTmp); SetDlgItemTextA(hWnd,ID_EDIT,cBuf); } else if( pInteralData->numeric.flag == UINF_INTEGER ) { //doto } } else if(pInteralData->type == UDET_ARRAY) { iTmp = pInteralData->strings.pos + factor * -1; if(iTmp < 0 ||iTmp > pInteralData->strings.count) return; pInteralData->strings.pos = iTmp; SetDlgItemText(hWnd,ID_EDIT,pInteralData->strings.pStrings[iTmp]); } } void OnDestroy(HWND hWnd) { UPDOWNEDIT_INTERNAL_DATA *pInteralData; int i; pInteralData = (UPDOWNEDIT_INTERNAL_DATA*) GetWindowLongPtr(hWnd,GWLP_USERDATA); if(pInteralData->type == UDET_ARRAY) { for(i = 0; i < pInteralData->strings.count; i++) { free(pInteralData->strings.pStrings[i]); } free(pInteralData->strings.pStrings); } free(pInteralData); } etc.h > #pragma once #include <windows.h> #include <CommCtrl.h> #include <WindowsX.h> #pragma comment(lib,"ComCtl32.Lib") #pragma comment(linker,"\"/manifestdependency:type = 'win32' \ name = 'Microsoft.Windows.Common-Controls' \ version = '6.0.0.0' \ processorArchitecture = '*' \ publicKeyToken = '6595b64144ccf1df' \ language = '*'\"") Το τελευταιο εχει να κανει με το initcommonctrlex, εγω δεν το καλω, αλλα φτιαχνω ενα embeded manifest για τα commctl v6, ψαξε πως το κανεις αυτο για τον compiler που εχεις http://www.youtube.com/watch?v=NhLqO4Q0P64
migf1 Δημοσ. 13 Μαΐου 2012 Μέλος Δημοσ. 13 Μαΐου 2012 Thanks για τον κώδικα! Πιστεύω πως όντως τελικά παραείναι πολύπλοκος. Προς το παρόν θα αρκεστώ στον τρόπο του 1ου ποστ, που προσωπικά τον βρίσκω πολύ απλούστερο κι εξίσου λειτουργικό για τις ανάγκες μου. Εκτός αν τα πάρω κρανίο πάλι και ξαναγυρίσω στο GTK ... ΥΓ. btw, εκεί τα SpinButtons (έτσι τα λέει) συμπεριλαμβάνονται στα στάνταρ widgets (έτσι λέει τα controls) με αποτέλεσμα η συνολική τους διαχείριση να είναι σκάρτες 20 γραμμές κώδικα: http://developer.gno...SpinButton.html
migf1 Δημοσ. 17 Μαΐου 2012 Μέλος Δημοσ. 17 Μαΐου 2012 Δεν ανοίγω άλλο νήμα, νομίζω δεν υπάρχει λόγος... ας τα έχουμε όλα σε αυτό. Επειδή έχω πήξει στο διάβασμα, θυμάται κανείς απέξω αν πρέπει να καταστρέφουμε μόνοι μας controls που δημιουργούμε με CreateWindowEx() στο WM_INITDIALOG message ενός modal Dialog; Συγκεκριμένα έχω αυτή την ρουτίνα που δημιουργεί ένα Tooltip στο δοθέν item ενός Dialog... > /*******************************************************//** * @brief Create a tooltip for an item in a dialog box. * * @param hDlg Window handle of the dialog box. * @param idItem Identifier of an dialog box item. * @param pszText String to use as the tooltip text. * * @return The handle to the tooltip. *********************************************************** */ HWND DlgCreateTooltip( HWND hDlg, int idItem, TCHAR *pszText ) { HWND hItem = NULL; HWND hTooltip = NULL; TOOLINFO toolinfo = { 0 }; // near initialization if (!hDlg || !idItem || !pszText) return NULL; /* Create the tooltip window (g_hInst is the global instance handle). */ hItem = GetDlgItem(hDlg, idItem); hTooltip = CreateWindowEx( 0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, // | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hDlg, NULL, g_hInst, NULL ); if (!hItem || !hTooltip) return (HWND)NULL; /* Associate the tooltip with the item. */ toolinfo.cbSize = sizeof(TOOLINFO); toolinfo.hwnd = hDlg; toolinfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; toolinfo.uId = (UINT_PTR) hItem; toolinfo.lpszText = pszText; SendMessage( hTooltip, TTM_ADDTOOL, 0, (LPARAM) &toolinfo ); return hTooltip; } Την καλώ στο WM_INITDIALOG message ενός Dialog για να προσθέσω tooltip σε μια εικόνα που περιέχει το Dialog... > switch( Message ) { case WM_INITDIALOG: TADataDlgInit( hDlg, &g_tadataDlg ); hTooltip = DlgCreateTooltip( hDlg, IDBUT_TADATA_LOGO, TEXT("This is a tooltip") ); Χρειάζεται να το κάνω DestroyWindow( hTooltip ); πριν ή μετά το EndDialog(); ?
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα