Ihan liian usein kysyttyjä kysymyksiä ohjelmoinnista ja kuvauskielistä

Taustaa

Jutellessani Ohjelmointiputkan keskustelussa ja IRC:ssä olen aivan liian usein saanut vastata samoihin kysymyksiin. Sen sijaan, että kirjoittaisin aina vastauksen uudelleen, päätin säästää vaivojani ja kirjoittaa tämän FAQ –sivun.

Sisällys

  1. Kieliriippumattomat

    1. Miten saan ohjelmani käynnistymään Windowsin mukana?
  2. Visual Basic

    1. Miten saan PictureBoxin niin, ettei se mene toisen Boxin läpi?
    2. Mistä saan Visual Basic –kääntäjän ilmaiseksi?
    3. Miten voin simuloida hiiren liikettä ja klikkauksia?
    4. Miten kirjoitan Windowsin rekisteriin?
  3. PHP

    1. Miksi saan virheilmoituksen Cannot modify header information - headers already sent by [...]?
  4. C

    1. Miksi C-konsoliohjelmani vain välähtää ruudulla?
  5. HTML/CSS

    1. Miten saan CSS:llä taulukosta kaikki välit pois?
    2. body –elementin marginaalien poistaminen CSS:llä ei onnistu Operassa. Mikä avuksi?
    3. Miten keskitän vaakatasossa lohkotason elementin niin, että se keskittyy kaikissa selaimissa?

Kieliriippumattomat

Miten saan ohjelmani käynnistymään Windowsin mukana?

Kirjoitamalla polun ohjelman binääriin rekisteriin osoitteeseen HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run Kannattaa kiinnittää erityistä huomiota mahdollisiin välilyönteihin polussa, jolloin polku pitää laittaa lainausmerkkien sisään.

Visual Basic

Miten saan PictureBoxin niin, ettei se mene toisen Boxin läpi?

Periaate on simppeli: ennen liikkuvan boksin liikuttamista tarkista, onko se liikkumassa “esteen” päälle. Jos on, älä liikuta. Usein nähty versio liikuttaa ensin ukkoa, katsoo sitten, liikuttiinko esteen päälle, ja jos näin kävi, liikuttaa sitä takaisin. Tämä ei kuitenkaan ole hyvä ratkaisu, sillä se aiheuttaa ylimääräistä tärinää ja välkkymistä. Koordinaatteja kirjoitellessa kannattaa pitää mielessä, että Pic.Left ja Pic.Top kertovat objektin vasemman ylänurkan sijainnin. Muut kulmat saadaan lisäämällä noihin objektin korkeus ja/tai leveys. Seuraava kaaviokuva saattaa auttaa hahmottamisessa:

[Kaaviokuva]

Käytännön toteutus oikein tehdystä törmäystarkistuksesta voisi näyttää esimerkiksi seuraavalta. Luo lomakkeelle kaksi PictureBoxia, picUkko ja picEste ja aseta lomakkeen ScaleMode –ominaisuus pikseleiksi (3) sekä KeyPreview –ominaisuus trueksi.

'Määritellään vakiona, kuinka monta pikseliä liikutaan kerrallaan
Const NOPEUS As Integer = 3

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    Select Case KeyCode
        Case vbKeyUp
            'Tarkistetaan, ettei olla menossa esteen päälle
            If picUkko.Top < (picEste.Top + picEste.Height + NOPEUS) And _
            (picUkko.Top + picUkko.Height - NOPEUS) > picEste.Top And _
            picUkko.Left < (picEste.Left + picEste.Width) And _
            (picUkko.Left + picUkko.Width) > picEste.Left Then
                'Jos kaikki ehdot täyttyivät näin on, ei liikuteta
                Exit Sub
            End If
            'Muuten voidaan liikuttaa ukkoa
            picUkko.Top = picUkko.Top - NOPEUS
        Case vbKeyRight
            If picUkko.Top < (picEste.Top + picEste.Height) And _
            (picUkko.Top + picUkko.Height) > picEste.Top And _
            picUkko.Left < (picEste.Left + picEste.Width - NOPEUS) And _
            (picUkko.Left + picUkko.Width + NOPEUS) > picEste.Left Then
                Exit Sub
            End If
            picUkko.Left = picUkko.Left + NOPEUS
        Case vbKeyDown
            If picUkko.Top < (picEste.Top + picEste.Height - NOPEUS) And _
            (picUkko.Top + picUkko.Height + NOPEUS) > picEste.Top And _
            picUkko.Left < (picEste.Left + picEste.Width) And _
            (picUkko.Left + picUkko.Width) > picEste.Left Then
                Exit Sub
            End If
            picUkko.Top = picUkko.Top + NOPEUS
        Case vbKeyLeft
            If picUkko.Top < (picEste.Top + picEste.Height) And _
            (picUkko.Top + picUkko.Height) > picEste.Top And _
            picUkko.Left < (picEste.Left + picEste.Width + NOPEUS) And _
            (picUkko.Left + picUkko.Width - NOPEUS) > picEste.Left Then
                Exit Sub
            End If
            picUkko.Left = picUkko.Left - NOPEUS
    End Select
End Sub

Kun esteitä halutaan useampi, kuin yksi, ne kannattaa laittaa taulukkoon (array). Muuten periaate on täysin sama.

Mistä saan Visual Basic –kääntäjän ilmaiseksi?

Laillisesti et mistään. Visual Basic 5:sta on olemassa ilmainen “Control Creation Edition”, jolla tosin ei voi tehdä binäärejä (exe–tiedostoja). Visual Basic 6:sta on tietääkseni olemassa ilmainen “Learning Edition”, jota tosin en ole onnistunut mistään löytämään (tuli ilmeisesti joidenkin kirjojen mukana), mutta oletettavasti silläkään ei voi kääntää binäärejä. Lisäksi toisin kuin usein väitetään Visual Basic 3:a ei ole koskaan julkaistu ilmaislevitykseen.

Jos VB.NET kelpaa, voit käyttää joko .NET Framework SDK+SharpDevelop -yhdistelmää tai Visual Basic .NET 2005 Express Editionia, jonka saa ilmaiseksi Microsoftilta.

Miten voin simuloida hiiren liikettä ja klikkauksia?

WinAPIn funktioilla SetCursorPos ja mouse_event. Alla koodiesimerkki.

Private Declare Function SetCursorPos Lib "user32.dll" _
(ByVal x As Long, ByVal y As Long) As Long
Private Declare Sub mouse_event Lib "user32" Alias "mouse_event" _
(ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, _
ByVal cButtons As Long, ByVal dwExtraInfo As Long)

Private Const MOUSEEVENTF_LEFTDOWN As Long = &H2
Private Const MOUSEEVENTF_LEFTUP As Long = &H4

Private Sub LiikutaJaKlikkaa(x As Long, y As Long)
	'Liikutetaan hiiri koordinaatteihin
	Call SetCursorPos(x, y)
	'Klikataan hiirellä
	Call mouse_event(MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0&, 0&, 0&, 0&)
End Sub

Koordinaatit ovat pikseleitä ruudun vasemmasta yläreunasta.

Miten kirjoitan Windowsin rekisteriin?

Windows API:n rekisterifunktioilla. Alla copypaste-esimerkki:

'Muutamia vakioita
Private Const HKEY_CURRENT_USER As Long = &H80000001
Private Const READ_CONTROL As Long = &H20000
Private Const STANDARD_RIGHTS_WRITE As Long = (READ_CONTROL)
Private Const KEY_SET_VALUE As Long = &H2&
Private Const KEY_CREATE_SUB_KEY As Long = &H4&
Private Const SYNCHRONIZE As Long = &H100000
Private Const KEY_WRITE As Long = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or _
KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
Private Const REG_SZ As Long = 1&

Private Type SECURITY_ATTRIBUTES
	nLength As Long
	lpSecurityDescriptor As Long
	bInheritHandle As Long
End Type

'Funktioiden esittelyt
Private Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias _
"RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _
ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions As Long, _
ByVal samDesired As Long, ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByRef phkResult As Long, ByRef lpdwDisposition As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) _
As Long
Private Declare Function RegSetValueEx Lib "advapi32.dll" Alias _
"RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
ByVal Reserved As Long, ByVal dwType As Long, ByRef lpData As Any, _
ByVal cbData As Long) As Long

Public Function KirjoitaRekisteriin(Polku As String, Avain As String, _
Arvo As String) As Long
	Dim Hanska As Long, Olemassa As Long
	Dim SecAttrs As SECURITY_ATTRIBUTES

	'NT-Windowsit vaativat rekisteriin kirjoittajalta oikeuksia, joita
	'pyydetään välittämällä RegCreateKeyEx:lle SECURITY_ATTRIBUTES
	'-tyyppinen struct
	With SecAttrs
		.nLength = Len(SecAttrs)
		.lpSecurityDescriptor = 0&
		.bInheritHandle = 1&
	End With

	'Avataan rekisteriavain, luodaan se, jos sitä ei jo ennestään ole
	'olemassa
	Call RegCreateKeyEx(HKEY_CURRENT_USER, Polku, 0&, "", 0&, _
	KEY_WRITE, SecAttrs, Hanska, Olemassa)

	'Kirjoitetaan arvo sinne
	KirjoitaRekisteriin = RegSetValueEx(Handle, Avain, 0&, REG_SZ, _
	ByVal Arvo & vbNullChar, Len(Arvo & vbNullChar))

	'Suljetaan rekisteriavain
	Call RegCloseKey(Handle)
End Function

PHP

Miksi saan virheilmoituksen Cannot modify header information - headers already sent by [...]?

HTTP protokolla määrittää, että otsakkeet tulevat ennen dataa, ei sen keskellä, ei sen jälkeen. Jos käytät PHP:tä otsakkeiden lähettämiseen tulee usein tilanne, jossa palvelin on jo lähettänyt dataa asiakkaalle, eikä HTTP-otsakkeita enää voi lisätä tähän väliin. PHP odottaa kyllä ensimmäiseen tulostukseen asti, mutta sen jälkeen otsakkeita ei voi muuttaa, koska ne on lähetetty jo. Ongelman korjaaminen on kuitenkin helppoa: älä tulosta mitään ennen niitä otsakkeita. Jos edellämainitun neuvon noudattaminen kuitenkin jostain syytä tuntuu kohtuuttoman hankalalta, voi ongelman kiertää puskuroimalla tulostuksen.

Ja eritoten käytettäessä header() -funktiota tiedostossa, joka liitetään toiseen tiedostoon kannattaa muistaa, että myös “tavallinen” HTML lasketaan tulostukseksi, mitä otsakkeiden lähettämiseen tulee. Aloittavan <?php –tagin tulee myös olla tiedostossa ihan ensimmäisenä, ensimmäisellä rivillä. Jo pelkkä välilyönti tai tyhjä rivi ennen aloitustagia on “tulostusta”.

Keksit (cookiet) lähetetään myös asiakkaalle HTTP-otsakkeissa, ja PHP:n sessiofunktiot käyttävät ensisijaisena tallennustapana keksejä, joten kaikki edellämainittu koskee myös setcookie() ja session_start() -funktioiden käyttöä.

C

Miksi C-tekstitilaohjelmani vain välähtää ruudulla?

Koska käynnistät sen väärällä tavalla. Tekstitilaohjelmat on tarkoitettu käynnistettäväksi komentoriviltä, ei naksuttelemalla ikoneja.

Avaa uusi komentorivi (Windows 9x:ssä Start > Run > command, NT:ssä Start > Run > cmd), vaihda hakemistoon, jossa ohjelmasi on ja aja kirjoittamalla ohjelman nimi. Ta-da! kaikki tulostus jää siihen komentorivi-ikkunaan, jonka juuri avasit ja voit tarvittaessa vaikka rullata ikkunaa takaisinpäin katsoaksesi, mitä aiemmin tapahtui.

Mahdollisena purkkaratkaisuna voi laittaa kutsun funktioon getchar (löytyy samasta headerista, kuin se printf:kin) juuri ennen kuin poistut pääohjelmasta, jolloin ikonistakin käynnistetty ohjelma jää ruudulle odottamaan käyttäjän näppäimenpainallusta.

HTML/CSS

Miten saan CSS:llä taulukosta kaikki välit pois?

table {
	border-collapse: collapse;
}

td {
	padding: 0;
}

Vaihda selektoreita tarpeen mukaan niin, etteivät ne sotki muita taulukoita. Jos käyttämäsi doctype laukaisee standarditilan lisää lisäksi td img {display: block;}. Testattu ja toimivaksi havaittu seuraavilla selaimilla: IE6, Mozilla 1.7 (Firefox 0.9.x), Opera 7.5x.

body –elementin marginaalien poistaminen CSS:llä ei onnistu Operassa. Mikä avuksi?

Operassa body –elementillä on oletuksena täytettä (padding) marginaalejen (margin) sijaan, jolloin marginaalejen asettaminen nollaksi ei luonnollisestikaan muuta näkyvää tulosta miksikään. Haluttuun tulokseen pääsee yksinkertaisesti nollaamalla sekä marginaalit, että täytteen.

body {
	margin: 0;
	padding: 0;
}

Ja ennenkuin kiroat Operan “typerää toteutusta” tiedä, että W3C:n esimerkkioletustyylitiedostossa HTML4:ää varten body –elementille on merkattu täytettä marginaalien sijaan :)

Miten keskitän vaakatasossa lohkotason elementin niin, että se keskittyy kaikissa selaimissa?

Oikea tapa lohkotason elementin keskittämiseenhän on asettaa sen vasen ja oikea marginaali samoiksi. Tämä ei kuitenkaan keskitä elementtiä Windowsin Internet Explorerissa. IE virheellisesti keskittää kuitenkin lohkoelementin, jos sille asettaa text-align: center; Ongelmana tässä on kuitenkin se, että oikein toimivat selaimet keskittävät sen sijaan lohkoelementin sisällä olevan inline-sisällön. Voimme kuitenkin käyttää tätä bugia hyödyksemme:

.keskitetty {
	margin-left: auto;
	margin-right: auto;
	text-align: center;	/* huijataan IE keskittämään elementti */
}

.keskitetty>* {
	text-align: left;	/* kumotaan huijauksen vaikutus oikein
				toimiville selaimille */
}
Copyright © 2004-2006 Karri “Blaze” Kahelin
Viimeksi päivitetty: 2006-08-28