Newsgroup: it.comp.programmare.win32
Titolo: [Regioni] - come selezionare piu' controlli??

Ciao, ho la necessita' di selezionare piu' controlli tramite un rettangolo
di selezione, un po come fanno gli ambienti di sviluppo visuali (Delphi, VB,
VC++ ed altri), mi e' stato detto che se non voglio impazzire a calcolare la
posizione tramite le coordinate e le dimensioni, devo utilizzare le regioni
(Regions), che pare possano restituire gli handle dei controlli in esse
contenuti... forse non sono stato molto chiaro!
Sapete dirmi qualcosa o farmi qualche esempio...
grazie, ciao Davide
/ - / - | - \ - \
Davide Piras
pir...@engineer.com
\ - \ - | - / - /

 contenuti... forse non sono stato molto chiaro!
Non conosco un'API che, data una Region, ti elenchi le handle dei
controlli in essa contenuti.
Una Region e` comoda perche` l'API RectInRegion ti dice se una
qualsiasi parte di un dato rettangolo e` contenuta nella data
Region.  E` piu` comoda e rapida di IntersectRect se devi fare
molti test... ma per costruire su di questo "le handle dei controlli
contenuti" nella Region, devi comunque:
    chiamare una EnumChildWindows sul dialogo i cui
        controlli vuoi selezionare, passando come
        puntatore alla funzione da usare l'indirizzo di:
    una tua funzione che, data l'HWND di un controllo,
        ne scopre il rettangolo (con GetWindowPlacement;
        GetWindowRect torna le cose in coordinate di
        schermo, mentre la tua Region e`, immagino,
        definita internamente al dialogo), lo testa con
        RectInRegion, e se del caso "accumula" l'HWND
        in questione in una opportuna struttura dati.
Spero che queste indicazioni ti bastino... se no, posta ancora,
e scrivero` un esempietto (non lo faccio subito per il caso che
a qualcuno venga in mente una soluzione + semplice, visto
che ora non ho il tempo di pensarci:-).
Alex

 forse non sono stato molto chiaro!
In effetti no, devi spiegare meglio cosa vuoi fare.
--
Bye! Lorenzo Lutti (
http://www.geocities.com/SiliconValley/Peaks/6258/
)

 aree rettangolari, e` inutile usare le regioni.
I controlli sono tutti rettangolari, perche' e' inutile usare le regioni?
ciao Davide

 I controlli sono tutti rettangolari, perche' e' inutile usare le regioni?
Semplicemente perche` e` immediato sapere se un rettangolo e` contenuto in un
altro rettangolo, non importa usare le funzioni per le regioni (che sono lente
e in questo caso renderebbero anche tutto piu` complesso). Chiamando
GetWindow() la prima volta con GW_CHILD e le volte successive con GW_HWNDNEXT
puoi agevolmente "scorrere" tutti gli handles; con GetWindowRect() puoi trovare
il rettangolo che li contiene. Cosi` a braccio:
// rcSelection contiene il rettangolo che hai selezionato
HWND hwnd = GetWindow( hParent, GW_CHILD);
RECT rc;
while( hwnd != NULL)
{
    GetWindowRect( hwnd, &rc);
    if( rc.top >= rcSelection.top &&
        rc.bottom <= rcSelection.bottom &&
        rc.left >= rcSelection.left &&
        rc.right <= rcSelection.right)
    {
        // questo controllo e` da selezionare!
    }
    hwnd = GetWindow( hwnd, GW_HWNDNEXT);


     {
Scusa, ma perche` dici che questo codice e` "piu` complesso" di
    if(RectInRegion(hRgn, rc))
    {
???
A me sembra che l'uso della RectInRegion sia invece una notevole
semplificazione rispetto al test che tu proponi.
Naturalmente, l'operazione di inizializzazione
    HRGN hRgn = CreateRectRgnIndirect(&rcSelection);
si fa una volta sola, fuori dal loop, e neppure essa e` complessa,
come pure la DeleteObject da fare alla fine.
Non ho mai misurato le prestazioni di RectInRegion, con una
region rettangolare, rispetto a quelle di un test esplicito; puo`
darsi quindi, per quel che ne so, che in situazioni in cui le
prestazioni sono assolutamente critiche, la maggiore complessita`
del test esplicito da te proposto "valga la candela".
Ma per usi tipici (rettangolo di selezione teste` disegnato
interattivamente, successiva operazione interattiva) i pochi
microsecondi di differenza fra le due soluzioni non possono
fare una differenza sostanziale.
E` vero che il RectInRegion esegue un test diverso da quello
da te proposto, cioe` se il rettangolo e la regione abbiano una
qualche intersezione non vuota, e non, invece, se il rettangolo
sia _interamente contenuto_ nella regione.  Le region, e`
chiaro, permettono una totale flessibilita`, grazie a
CombineRgn, ma posso anche capire che uno non voglia
imbarcarsi su questa strada (che puo` apparire un poco
complessa:-), e preferisca "fare i test a mano".  Personalmente,
pero`, preferisco la generalita` e flessibilita` delle API.
Supponi, ad esempio, che le window che vuoi testare
possano essere non-rettangolari (per cui la relativa
GetWindowRect ne torna solo la "bounding box", non
la "vera" finestra, che non e` un rettangolo); faccio
presente che le finestre non-rettangolari esistono sin da
NT 3.51 e Win95, quindi non sono certo una novita`.
La soluzione a colpi di >= e <= non si generalizza a
questo caso; quella a colpi di region e API si`...!-)
Alex

 possano essere non-rettangolari
Non per niente ho chiesto all'altro utente se lo erano o meno. Nel caso che non
lo fossero state, io avrei comunque valutato l'opportunita` di usare il loro
"bounding rectangle" (che deve si` essere calcolato con le regioni, ma una
tantum per ogni controllo).


 tantum per ogni controllo).
In realta` puoi usare la GetWindowRect per ottenere il bounding rectangle
di una finestra qualsiasi (anche non rettangolare).  Ma pensare di
cambiare le specifiche della GUI di un programma (considerare una
finestra "compresa" se la sua _bounding box_ interseca il rettangolo,
oppure se la _finestra vera e propria con la sua forma_ lo fa?), non
sulla base di "fattori umani", bensi` su quella di permettere una
ottimizzazione probabilmente irrilevante "per questioni di principio"...
beh, mi mancano le parole.
Questa si` che e` una questione di principio.  Le interfacce dei programmi
si fanno _per essere massimamente usabili, chiare, ecc ecc_, NON per
permettere a qualcuno di evitare delle API che gli stanno antipatiche.
Alex

 oppure se la _finestra vera e propria con la sua forma_ lo fa?)
Non si tratta di cambiare le specifiche di una GUI, ma piu` semplicemente di
ricordare le piu` elementari nozioni di geometria e ragionare. Non ti sto a
fare un disegnino ma mi sembra piuttosto ovvio che, quale che sia la forma di
un oggetto, per sapere se esso sta dentro a un rettangolo sia sufficiente
considerare il rettangolo che lo circoscrive...
--
Bye! Lorenzo Lutti
http://www.geocities.com/SiliconValley/Peaks/6258/
P.S. Ah, per inciso: nel nostro caso la funzione che citi, ossia
RectInRegion(), non si potrebbe nemmeno usare. Noi parlavamo di una selezione
rettangolare e di oggetti non rettangolari, non viceversa; quindi usare le
API delle regioni anziche` i RECT sarebbe ancora piu` comicamente contorto,
perche` dovremmo chiamare CombineRgn() e EqualRgn() per ogni singolo
controllo...

 perche` dovremmo chiamare CombineRgn() e EqualRgn() per ogni singolo
Spiegami, spiegami cosa dobbiamo chiamare a fare la EqualRgn.  Spiegamelo,
PER FAVORE, visto che la CombineRgn (e non occorre essere dei geni per
saperlo, basta avere un MINIMO di competenza relativa ad un argomento,
prima di sputar sentenze su di esso...!) torna NULLREGION se, e solo se,
la regione risultante dalla combinazione e` vuota, e cosi`, mi pare, e`
SEMPRE stato per TUTTI i release di Win32.
Quindi, per sapere se una finestra, di handle hw e forma arbitraria, ha una
intersezione non vuota con una regione R, basta fare:
    GetWindowRgn(hw, hrtemp);
    if(NULLREGION==CombineRgn(hrtemp,hrtemp,R,RGN_AND))
        // nessuna intersezione
Similmente, per sapere se essa e` interamente contenuta in R,
    if(NULLREGION==CombineRgn(hrtemp,hrtemp,R,RGN_DIFF))
        // interamente contenuta
Spiega, spiega la "comica contorsione" (e soprattutto la necessita` di
EqualRgn, che asserisci con tanta sicumera) nell'uno, o nell'altro, di
questi casi.
Se sai che R e` una regione rettangolare, e se GetWindowRect
torna sempre la effettiva bounding-box della vera forma della
finestra (quest'ultimo fatto non e` chiaro dalla documentazione;
puo` darsi che sia ammesso, come rettangolo tornato da questa
API, anche uno piu` ampio della bounding-box della vera forma),
puoi sostituire il _secondo_ caso con i 7 operatori (4 di confronto,
3 di congiunzione logica) che ritieni "meno complessi" dell'unica
chiamata suddetta; se le specifiche sono quelle del primo caso
(si vuol sapere se intersezione e` non-nulla, non se lo sia o meno
la differenza), la bounding box non interessa (eccetto, se del caso,
come "ottimizzazione spinta": se il controllo delle bounding box
risulta molto rapido, e risparmia nella gran parte dei casi il resto
del lavoro, puo` meritare di farlo come "winnowing" preliminare,
passando all'effettivo controllo delle region solo una minoranza
dei casi -- SE, naturalmente, le prestazioni di questa specifica
operazione risultano cruciali al programma nel suo complesso).
Non mi paiono da prendere sul serio le tue considerazioni di
cosiddetta "ingegneria del software" da cui risulterebbe che,
reimplementando nel proprio codice la funzionalita` di una
API invece di chiamarla, si otterrebbe miglior qualita` grazie
ad un fantomatico "disaccoppiamento" ed eventuali aggiramenti
di eventuali bug delle API stesse.  L'accoppiamento del tuo
codice al framework che il codice stesso ha scelto di usare (ad
esempio le API) e` ovviamente fortissimo e inevitabile, e i bug
possono trovarsi con almeno altrettanta probabilita` nel codice
che scrivi tu, come in quello che vuoi evitare di riusare.  Se
no, perche` si riuserebbe *qualsiasi* codice da una libreria
esistente...?
Parallelo: ho una stringa tipo C (array di char con 0 alla fine)
che so contenere sole cifre (1 o +).  Come la trasformo nel
numero intero equivalente?
Risposta: riusando funzioni esistenti in libreria, come atoi,
*naturalmente*.  Potresti scrivere codice piu` efficiente (sai
che non c'e` un segno iniziale, quindi puoi risparmiarti di
controllarlo, mentre atoi deve cominciare con quel controllo;
puoi sfruttare il fatto che dopo le cifre c'e` uno 0 binario
di terminazione, cosa su cui atoi non puo` contare, ecc);
potresti evitare eventuali bachi di atoi; ma, come e` ovvio,
_il gioco non vale la candela_ -- la possibilita` di introdurre
un bug nel tuo codice, e la complicazione risultante dall'avere,
invece di una sola chiamata "num=atoi(p);", qualcosa come
    "for(num=0;*p;++p) num=num*10+*p-'0';"
o il piu` ottimizzato (risparmia una moltiplicazione):
    "num=*p++ - '0'; while(*p) num=num*10+ *p++ - '0';"
indicano chiaramente che _il riuso del codice gia` esistente
(e testato...) in libreria e` la migliore strategia_, con buona
pace delle tue pretestuose "considerazioni di Sw. Eng"!
Alex

         // interamente contenuta
Per chiudere il thread rispondero` per punti, in ordine di serieta`
descrescente e idiozia crescente. Cosi` eventualmente avrai dei buoni motivi
(per ora non mi sembrava di avertene dati, quindi voglio recuperare) per
controbattere con risposte palesemente ostili e sgarbate come hai fatto finora.
1-La prima meta` del tuo messaggio l'hai dedicata a rispondere a un mio piccolo
inciso, non per niente riportato alla fine in un post scriptum. In tale inciso
mi limitavo a evidenziare un tuo errore introducendone - questo e` vero - uno a
mia volta. Ma tu non sei stato cosi` umile da ammettere il tuo errore (ed 'en
passant' facendo notare il mio), ne` tantomeno ha pensato di seguire il saggio
approccio di Wittgensteiniana memoria di onorare il silenzio. No! Anzi, hai
basato tutto il tuo attacco sul mio errore. E` come se io avessi fatto un
errore di ortografia e tu, anziche` considerare il succo del discorso, mi
avessi insultato perche` non conosco l'italiano.
2-La seconda meta` del tuo messaggio l'hai dedicata a fornire pregevoli offese
e interessanti esempi di come sia meglio chiamare le API piuttosto di
riscriversi Windows 95 da zero, nel caso che qualcuno ne dubitasse. Non notando
pero` il piccolo particolare che il mio discorso sull'isolamento era
palesemente *paradossale*, proprio per evidenziare la stupidita`
dell'applicazione regole di ingegneria del software in una simile banalita`.
3-Citando il famoso distico "le chiacchiere stanno a zero", sarei veramente
curioso di sapere quanti, avendo una selezione rettangolare, deciderebbero non
solo di calcolare le regioni dei controlli da selezionare, ma anche di
convertire la selezione rettangolare in regione solo per il gusto di potere
usare CombineRgn.
4-Nemmeno l'uso delle regioni nel modo che consigli e` abbastanza
human-readable e human-behavioural! Dopotutto un essere umano riconoscere a
colpo d'occhio se degli oggetti sono dentro a una selezione o meno, non ha
bisogno di fare un test per ogni oggetto. Quindi io proporrei di considerare
ogni combinazione e permutazione delle regioni, per poter identificare con una
sola CombineRgn il gruppo di oggetti che sono contenuti nella selezione. E`
vero, alla fine magari avremo da fare milioni di controlli anche con poche
decine di oggetti, ma avremo un singolo controllo che ha successo!
5-Di`, la verita`, tu in realta` lavori per la Microsoft e sei quello che ha
sviluppato le funzioni per le regioni di Win32. Quindi in realta` parli cosi`
perche`, anche se sai che le normali funzioni per le regioni sono lente,
esistono altre API non documentate tipo _MyCombinRgnThatIsReally32bit() e
_MyFunctionThatDeterminesIfSomeNonRettangularControlsAreContainedInARegion(),
usate negli Office della M$, che sono molto piu` veloci e comode di quelle
inutili idiozie che rispondono al nome di operatori di confronto/logici.
Bye! Lorenzo Lutti
http://www.geocities.com/SiliconValley/Peaks/6258/
P.S. Non te la prendere, semplicemente non avevo piu` voglia di stare serio e
volevo trovare un metodo per uscire dal thread nel modo piu` stupido possibile.
;-)
BTW, se anche stavolta vuoi iniziare la tua risposta dal P.S., ecco un punto
aggiuntivo:
6-Dato che hai citato Ritchie (ah, davvero e` il padre del C? <eg>), non voglio
essere da meno e cito qualcuno anche io:
"Se possediamo una giusta teoria, ma ci limitiamo a farne oggetto di
conversazione e ad archiviarla senza metterla in pratica, allora questa teoria,
per quanto buona, non ha alcuna importanza".
Una tigre di carta in premio a chi scopre l'autore. :)

 a mia volta. Ma tu non sei stato cosi` umile da ammettere il tuo errore
(ed 'en
Secondo me, questo tuo non e` piu` un errore, e` una MENZOGNA.
Infatti, penso che tu debba sapere benissimo, a questo punto, che
stai dicendo il falso.  Di quale "mio errore" vai mai "evidenziando"...?
Tu stavi solo dicendo l'ovvieta` che RectInRegion testa se un rettangolo
"e` in" (=ha intersezione non nulla con) una region, mentre se quello
che vogliamo testare e` altro, altre API vanno chiamate (e hai sbagliato
nell'identificare quali, nel senso che, oltre a quella che serve allo scopo,
ne volevi chiamare in piu` un'altra, qui _totalmente_ superflua).
Sin dal mio primo post su questo thread avevo scritto "Le region, e`
chiaro, permettono una totale flessibilita`, grazie a CombineRgn" (e
nota che avevo gia` identificato correttamente l'API da usare per
questi test, se occorre la completa generalita`).  Dopodiche` tu ti
PERMETTI di dire, nel tuo messaggio dove, secondo te, staresti
"evidenziando un mio errore", che...: ``la funzione che citi, ossia
RectInRegion()''... in RISPOSTA a messaggi in cui _CITAVO_ cosi`
"clamorosamente" CombineRgn...?!
Non riesco a credere che qualcuno sia cosi` imbecille da lanciare
flame in risposta ad un messaggio, avendolo letto cosi` male da
pensare _veramente_ che io abbia detto che la totale flessibilita`
si ottiene con RectInRegion, quando, come ho appena citato,
dicevo cosi` esplicitamente che si ottiene con CombineRgn!!!
No, penso proprio che sia una menzogna, altrettanto deliberata
quanto sconsiderata (perche` era ovvio che non me la sarei
lasciata sfuggire, e perche` i lettori, che non sono scemi, sono
perfettamente in grado, ora, di valutare quale sorta mai di
individuo tu sia -- tale da lanciare menzogne, cosi` facili da
provare come tali, e addirittura in un newsgroup tecnico...!).
Viene voglia di provare la funzione di filtro di questo newsreader,
ma temo sia meglio tenerti d'occhio per evidenziare altre
eventuali future menzogne... si sa` mai!-)
Alex

 Viene voglia di provare la funzione di filtro di questo newsreader,
Ottima idea! Se pensi che ti capitera` spesso di reagire come uno squilibrato,
sono io a chiederti di mettermi nel killfile. Farai un grosso piacere anche a
me, non solo a te stesso. Inoltre potrai dedicarti a cose molto piu` urgenti e
importanti (cfr. MSDN Library, "HOWTO: 101 ways to get a life").
--


 importanti (cfr. MSDN Library, "HOWTO: 101 ways to get a life").
Dici che spendo troppo tempo ed energia ad aiutare gente
sulle news...?  Hai ragione, guarda, evitero` di scrivere quel
post, su come massimizzare le MDI Child Windows in MFC
"sin dalla nascita", che pensavo di fare per aiutare un certo LL.
Alex

 "sin dalla nascita", che pensavo di fare per aiutare un certo LL.
Non so cosa sia piu` pronunciato, se il tuo infantilismo oppure il tuo ego.
Credi forse di essere l'unica e ultima speranza di qualcuno? Scrivi perche` ti
senti unto da qualche divinita`?
Le rare volte che posto una domanda su questo NG, di solito lo faccio perche`
in quel momento non ho tempo per trovare rapidamente la risposta. Allora posto
il messaggio sperando che ci sia qualcuno in grado di rispondermi al volo; se
non c'e`, la risposta me la trovo da solo. Pensi che in due giorni non sia
riuscito a debuggare CMDIChildWnd::OnCreate() per vedere come funziona? Per
notare che basta aggiungere il flag WS_VISIBLE affinche` venga considerato
anche il flag WS_MAXIMIZE?


, 
al...@magenta.com
 says...
In questo thread Regioni VS le-quattro-disequazioni :) vedo solo due 
cose: la ragione teorica sta dalla tua parte, ma in pratica la decisione 
di Lorenzo in quel contesto e' giusta perche la specifica implementazione 
delle Region API in Win32 e' pessima...
C'e bisogno di flessibilita', anche in questi contesti decisionali, non 
credi?
le Win32API non sono da prendere come una black-box al 100%, IHMO
-- 
  . 
darX...@tin.it
      . 
darx...@wappi.com
 (GSM SMS)
   . Fido 2:335/241.5     . 
http://darxstar.cjb.net
  ICQ UIN# 11151997 -   
  trough Britannia: Gwydion the Mage <UO: EUROPA,now in Trisinc>
---
I don't want my freedom: there's no reason for living, with a broken heart
 -- The Queen

 le Win32API non sono da prendere come una black-box al 100%, IHMO
Secondo me, e` meglio, visto che le implementazioni passate,
presenti, e future, sono molteplici, e spesso assai diverse.
Sicuramente, il "100%" e` un'astrazione; se esistono dei bug
(compresi, se e quando rilevanti, dei bug di _prestazioni_) sulla
implementazione di certe API su certe piattaforme importanti,
si e` costretti ad usare work-around (un esempio fra mille, ben
noto, e` che si deve evitare il piu` possibile il DDE, e se proprio
serve NON farlo con DDEml, causa bug ben noto e documentato
che causa piantamento dell'applicazione che usa DDEml se una
qualsiasi window top-level, dovunque nel sistema, non sta
servendo il proprio message-loop -- baco noto da 5 anni nella
Knowledge Base Microsoft, se non l'hanno rimediato in 5 anni
dubito che lo sistemeranno ora...:-).
Se io fossi costretto, ad esempio, a scrivermi del DDE a colpi
di stradannati messaggi, causa questo bug delle API DDEml,
di parole potrebbero uscirmene tante (molte di esse, del tutto
irripetibili:-), ma non mi verrebbe certo in mente di pensare
a chiamare *COMPLESSO* il codice che chiama DdeConnect
e compagnia... sarebbe codice, in confronto, molto piu`
_semplice_ di quello che sarei invece costretto a scrivere.
Alex

>presenti, e future, sono molteplici, e spesso assai diverse.
Si, cmq per le WIn32C questo discorso potrebbe anche andare bene
Sa perliamo del framework MFC...e' meglio partire dai SORGENTI, si lavora 
meglio


 meglio
Si`, la disponibilita` dei sorgenti e` sicuramente di grande aiuto: e`
la piu` chiara delle "documentazioni" per una libreria come MFC!-)
C'e` pero` anche una trappola, ben presentata da Brown, Malveau,
McCormick e Mowbray, nel loro buon libro "AntiPatterns", come
"Mini-AntiPattern: Dead End"... in sostanza, la grande tentazione
di _modificare un componente riusabile_ (per rimediare ad una
sua qualche mancanza, vera o presunta) -- i quattro autori fanno
un ottimo lavoro nel presentare tutte le magagne che seguono a
questa comprensibile ma pericolosissima scelta.
E ci si casca tutti, prima o poi... e` "il pericolo numero uno", sia
del software Open-Source, sia di quello che, pur proprietario, viene
comunque distribuito con sorgenti.
Alex