Siis,
Minulla on RECT-muuttuja, johon on haettu erään kontrollin sijainti ja koko (GetWindowRect). Sen jälkeen vaihdan ikkunan sijaintia (ja kokoa) SetWindowPos-komennolla. Jos kirjoitan kolmannen parametrin (top) kohdalle jonkin numeroarvon, ohjelma toimii hyvin, mutta jos laitan siihen suoraan RECT-muuttujan osia, kontrolli katoaa näkyvistä. Jos kukaan ei tajunnut, niin:
SetWindowPos(nappula, rectmuuttuja.left, rectmuuttuja.top, 100, 100, true);
...kontrolli katoaa. Tämä sama ongelma ei ilmene minkään muun parametrin kanssa.
Jotta tästä tulisi vieläkin epäselvempää; kontrolli ei katoa, jos vaihdan rectmuuttuja.top -> rectmuuttuja.top / 2.
Oletko tarkistanut, että mitä parametreja tuolle SetWindowPos-funktiolle noin ylipäätään pitää antaa?
Öh, joo... Parametrien sijainnin pitäisi olla oikein, koska jos kirjoitan kolmannen parametrin tilalle esim. 10, etäisyydeksi yläreunasta tulee 10.
Ei, eipä taida tulla. Funktio nimittäin ottaa MSDN:n mukaan seitsemän parametria, joista kahden ensimmäisen tyyppi on HWND. Viimeisen tyyppi taas on UINT ja se sisältää tiettyjä lippuja, joten antamasi true
on siinä ehdottomasti väärä vaihtoehto. Luultavasti tarkoitukseesi oikea arvo olisi SWP_NOZORDER, jotta voit huoletta antaa toiseksi parametriksi arvon 0
.
SetWindowPos(nappula, 0, r.left, r.top, 100, 100, SWP_NOZORDER);
Yleisesti WinAPI-ongelmien (ja muidenkin) kanssa kannattaa aloittaa tarkistamalla dokumentaatiosta, mitä parametrit ovat ja mitä ne tekevät.
Toisaalta eihän tuossa missään sanottu että kyseessä on Windows, joten MSDN voi olla väärä paikka katsoa. Myönnän toki, että Windows minullekin ensimmäisenä tulee mieleen. Mutta jos se kerran Juhkon mukaan toimii kuudella parametrilla...
Aivan, toinen realistinen vaihtoehto tietenkin on, että Juhko käyttää MFC:tä ja kyseessä on ikkunan jäsenfunktio, CWnd::SetWindowPos. Tällöin ensimmäinen parametri jää pois eli siirrettävää ikkunaa ei anneta lainkaan parametrina. Toisen (ts. nyt ensimmäisen) parametrin tyypiksi taas tulee const CWnd*
. Muut parametrit ovat ennallaan. Tässäkin tapauksessa ohje on sama: referenssi-ikkunaksi 0 ja lipuksi SQP_NOZORDER. Rivi varmaankin näyttäisi tältä:
nappula->SetWindowPos(0, r.left, r.top, 100, 100, SWP_NOZORDER);
Vai oliko tarkoitus sittenkin siirtää jotain muuta kuin tuota nappulaa?
Sori, toinen parametri jäi viestistä pois ihan vahingossa. Mun moka. Oikea (hieman muokattu) koodi on tässä:
#define AutoScretch(hwnd) GetWindowRect(hwnd,&meRect) ; GetWindowRect(hwnd ## Parent,&parentRect) ; SetWindowPos(hwnd,0,meRect.left,meRect.top,100,100,SWP_NOZORDER);
meRect
on siis se RECT-muuttuja, ja tätä makroa kutsutaan ikkunaproseduurin lopussa AutoScretch(ikkuna2), missä ikkuna2 on kontrolli ja ikkuna2Parent on parent-ikkuna.
En ole varma, mitä olen muuttanut - paitsi tuo SWP_NOZORDER - mutta nyt tämä ongelma tulee myös kolmannen parametrin (left) kohdalla.
Olen kokeillut myös MoveWindowin kanssa, mutta sekään ei toimi. -.-
Makroja ei minusta kannata tuossa käyttää, menevät vain muuttujat sekaisin. Jos käytät, niin laita se ainakin useammalle riville \-merkin avulla, jotta koodi selkenee.
Taitaa olla niin, että GetWindowRect palauttaa sijainnin ruudulla mutta SetWindowPos asettaa sijainnin suhteessa pääikkunaan. Jos ikkunaa ei tarvitse siirtää, voit lisätä mukaan lipun SWP_NOMOVE, jolloin antamillasi koordinaateilla ei ole merkitystä. (Tämä siis yhdistetään tai-operaatiolla eli |-merkillä SWP_NOZORDER-lippuun.) Muussa tapauksessa joudut muuttamaan koordinaatit ruudulta ikkunan koordinaatistoon. Windows 2000:sta alkaen tämä onnistuu MapWindowPoints-funktiolla, aiemmin täytyy kai laskea itse.
Metabolix kirjoitti:
Makroja ei minusta kannata tuossa käyttää, menevät vain muuttujat sekaisin.
Täh?
Metabolix kirjoitti:
Taitaa olla niin, että GetWindowRect palauttaa sijainnin ruudulla mutta SetWindowPos asettaa sijainnin suhteessa pääikkunaan.
Tiedän, tuo olikin vain esimerkki, mutta ikkuna katoaa vaikka siirtäisin pääikkunan vasempaan ylänurkkaan.
Metabolix kirjoitti:
Jos ikkunaa ei tarvitse siirtää, voit lisätä mukaan lipun SWP_NOMOVE
...kiitos.
Juhko kirjoitti:
Metabolix kirjoitti:
Makroja ei minusta kannata tuossa käyttää, menevät vain muuttujat sekaisin.
Täh?
Minusta on huono tapa tehdä makroja tai funktioita, joiden vaikutuksia ei voi kutsusta päätellä. Esimerkiksi seuraava funktio valittaisi peräti kolmesta puuttuvasta muuttujasta:
void funktio(HWND tmp_hwnd) { AutoScretch(tmp_hwnd); }
Vielä pahempi on, jos funktio sattuu käyttämään noita RECT-muuttujia aivan itse ja makro yllättäen muuttaakin ne joksikin muuksi. Virheen löytäminen ilman debuggeria olisi todella työlästä.
Aivan sama ongelma pätee pääsääntöisesti tilanteisiin, joissa funktiot muuttelevat globaaleja muuttujia, jos ei ole aivan selvää ja loogista, että näin tapahtuu.
Siksipä siis tuostakin toiminnosta olisi järkevintä tehdä oma funktionsa, joka sisältää tarvittavat muuttujat ja ottaa loput parametreina. Toinen vaihtoehto olisi tehdä makrosta funktiota muistuttava eli sijoittaa sen sisältö omaan lohkoonsa, jossa määritellään tarvittavat väliaikaiset muuttujat. Tällöinkin käytettävät osat pitäisi minusta ensisijaisesti antaa parametreina:
// Jos on pakko makroksi saada, niin edes näin. // Silmukka "do { ... } while (0)" ei ole välttämätön, mutta // se pakottaa laittamaan puolipisteen aina makron perään. #define SetHalfSizeAndCenter(hwnd, parent) \ do { \ RECT r; \ GetWindowPos(parent, &r); \ const int w = (r.right - r.left) / 2; \ const int h = (r.bottom - r.top) / 2; \ SetWindowPos(hwnd, 0, w / 2, h / 2, w, h, SWP_NOZORDER); \ } while (0)
// Parempi vaihtoehto: funktio void SetHalfSizeAndCenter(HWND hwnd, HWND parent) { RECT r; GetWindowPos(parent, &r); const int w = (r.right - r.left) / 2; const int h = (r.bottom - r.top) / 2; SetWindowPos(hwnd, 0, w / 2, h / 2, w, h, SWP_NOZORDER); }
Juhko kirjoitti:
Ikkuna katoaa vaikka siirtäisin pääikkunan vasempaan ylänurkkaan.
Teetkö siirron ehkä silmukassa? Tällöin yhdenkin pikselin heitto aiheuttaa toistuvan siirtymisen joka kierroksella, jolloin ikkuna juoksee aika vikkelästi pois.
En tietysti ilman testikoodia saa itse kokeiltua tuota, kun ei kiinnosta vapaaehtoisesti yrittääkään WinAPI:n käyttöä. ;)
Metabolix kirjoitti:
Minusta on huono tapa tehdä makroja tai funktioita...
Kiitos, täytyypä ruveta muuttelemaan turhimpia makroja funktioiksi. :)
Metabolix kirjoitti:
Aivan sama ongelma pätee pääsääntöisesti tilanteisiin, joissa funktiot muuttelevat globaaleja muuttujia, jos ei ole aivan selvää ja loogista, että näin tapahtuu.
Joo, mutta funktiot on nimetty niin, että olisi todella epätodennäköistä, että niitä esiintyisi jossakin muualla.
Metabolix kirjoitti:
Teetkö siirron ehkä silmukassa? Tällöin yhdenkin pikselin heitto aiheuttaa toistuvan siirtymisen joka kierroksella, jolloin ikkuna juoksee aika vikkelästi pois.
Kiitos vinkistä, saattaa hyvinkin johtua tästä. :)
ps. Metabolix, osaatko sinä oikeasti kaiken, mitä ohjelmoinnista tarvitsee osata?
Aihe on jo aika vanha, joten et voi enää vastata siihen.