Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB.NET: [VB 2008] Default- ja Cancel Button

Sivun loppuun

vesimies [18.10.2008 20:12:34]

#

Hei!

Mites VB 2008:ssa asetetaan nappulalle (Button) Default- ja Cancel-ominaisuudet? Eli Default Button on esimerkiksi "Laske" jonkin tekstiruudun vieressä; tällöin enterin painallus tekstiruudussa olisi sama kuin Laske-napin klikkaus.

VB6:ssahan tämä tehtiin vain asettamalla ominaisuusikkunassa CommandButtonin Default-ominaisuus arvoon True (jolloin kaikkien muiden CommandButtonien Default-ominaisuus muuttui automaattisesti arvoon False).

MS Visual Studio 2008 Documentation kertoo Button-luokalla olevan ominaisuus IsDefault: "Gets or sets a value indicating whether the button control is the default button." Eli kyseessä kai on hakemani ominaisuus. Nyt tulee tyhmä kysymys. Koska kyseinen ominaisuus on Protected, niin miten ihmeessä sen saa asetettua?!? Lomakkeen koodista se ei onnistu koska se katselee Button-objektia "ulkopuolelta". Tässä yritys:

Public Class frmTestiLomake

    Private Sub frmTestiLomake_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        btnKerro.isdefault() = True ' aiheuttaa tietysti virheen
    End Sub

    Private Sub btnKerro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnKerro.Click
        lblTulos.Text = Val(txtSyöttöLuku.Text) * 2
    End Sub

End Class

Entä miten Cancel-button tehdään? (Itse tehdyssä dialogi-ikkunassa on usein kätevä laittaa Sulje-napille Cancel-ominaisuus, jolloin Esc-napin painaminen missä tahansa tilanteessa sulkee ikkunan.)

Ps. Hieman nimeämiskäytännöistä VB .Netissä: Ohjausobjekteille kannattanee edelleen käyttää etuliitteitä "txt", "btn", "lbl" jne., mutta entä lomakkeille?

neau33 [19.10.2008 12:49:06]

#

Moikka vesimies!

olettaisin, että DefaultButton-ominaisuus voidaan asetella lennossa tyyliin...

Imports Microsoft.VisualBasic
Imports System.Windows.Forms

Public Class frmTestiLomake: Inherits Form

  Protected WithEvents MyDefaultButton As New Button

  Private Sub frmTestiLomake_Shown(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Shown

      Me.CancelButton = Me.btnPeruuta
      MyDefaultButton = Me.btnKerro
      MyDefaultButton.Focus

      'Ja voilà nyt kun painat Enter'iä niin...

  End Sub

  Private Sub btnKerro_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles btnKerro.Click
    Me.CancelButton.PerformClick
  End Sub

  Private Sub btnPeruuta_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles btnPeruuta.Click
    MsgBox("Enkä kerro...")
    MyDefaultButton.Focus
  End Sub

End Class

vesimies [19.10.2008 13:57:32]

#

Kiitos vastauksesta, Nea!

Cancel Button toimii täysin. :) Default Button sen sijaan ei... :( MyDefaultButtonin tekeminen ei muuta sitä asiaa, että oletusnappi saa fokuksen vain ikkunaa avattaessa. Eli kun fokus on tekstiruudussa, niin enterin painaminen ei vaikuta mitään.

Okei, nyt kai olisi pari tapaa hoitaa homma:
- Tehdään jokaiselle tarvittavalle kontrollille näppäinpainalluksen tapahtumankäsittely, ja tutkitaan painettiinko enteriä, ja jos niin klikataan oletusnappia koodista (voiko olla kömpelömpää, tätä en kyllä tee)
- Tehdään lomakkeelle samanlainen näppäinpainalluksen tapahtumankäsittely, ja lisäksi kerrotaan lomakkeelle että se nappaa kaikki näppäimet ennen tekstiruutua:

Me.KeyPreview = True ' tai ominaisuusikkunassa

Hetkonen tätähän pitää testata, miten tekstiruutu silloin käyttäytyy...

Nyt en kyllä saa millään selville miten se enter tunnistetaan. Näin olen yrittänyt:

Private Sub frmTestiLomake_KeyPress(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.KeyPressEventArgs) _
    Handles Me.KeyPress

    ' Miksei tämä vertailu onnistu:
    If e.KeyChar = System.Windows.Forms.Keys.Enter Then
        btnKerro.PerformClick()
    Else
        ' ei tarvi tehdä mitään, merkki menee teksikenttään
        ' (jos fokus on siellä)
    End If
    ' Error: Operator '=' is not defined for types 'Char' and 'System.Windows.Forms.Keys'.
    ' No mikä tyyppi se sitten on?
End Sub

Aika monimutkainen viritys, vaikka sen varmaan saakin toimimaan. Siihen verrattuna että asettaisi vain Default Buttonin. Mikähän nyt olisi paras tapa? Tokihan ohjelman saa toimimaan ilmankin tätä ominaisuutta mutta kyllä se lisää käyttömukavuutta todella paljon.

Muutenkin on näin aluksi VB6:n jälkeen sellainen olo kuin olisi ennen ajellut ladalla ja nyt löytää itsensä avaruusraketin ohjaamosta... Tietää että tämä on paljon tehokkaampi mutta ei osaa käyttää sen vertaa että pääsisi edes hieman rämistelemään eteenpäin. Mutta jospa se tästä.

OT: Mikä idea muuten on tuossa "Inherits Form"-kohdassa? Kokeilin ottaa sen pois, ja toimi ihan samalla lailla. Tiedän siis suunnilleen mitä perintä on, mutten ymmärrä miksi sitä tässä tarvii käyttää.

vesimies [19.10.2008 15:35:26]

#

No nyt sain sen toimimaan:

Public Class frmTestiLomake
    ' Muistipaikka sille oliko painettu näppäin enter vai jokin muu:
    Private oliEnter As Boolean

    Private Sub frmTestiLomake_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.KeyPreview = True ' varmistetaan että lomake ottaa näppäinpainallukset
        Me.CancelButton = Me.btnSulje
    End Sub

    ' Kun näppäintä painetaan, niin katsotaan mikä nappi se oli:
    Private Sub frmTestiLomake_KeyDown(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.KeyEventArgs) _
    Handles Me.KeyDown
        oliEnter = (e.KeyCode = Keys.Enter)
        ' no niin se on sitten muistissa
    End Sub
    ' Tämä tapahtuma tulee KeyDownin jälkeen:
    Private Sub frmTestiLomake_KeyPress(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.KeyPressEventArgs) _
    Handles Me.KeyPress
        If oliEnter Then btnKerro.PerformClick()
    End Sub

    ' Sitten varsinaiset nappulatapahtumat:
    Private Sub btnKerro_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnKerro.Click
        lblTulos.Text = (Val(txtSyöttöLuku.Text) * 10).ToString
    End Sub

    Private Sub btnPeruuta_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnSulje.Click
        Me.Close()
    End Sub

End Class

Edelleen otetaan vastaan helpompi tapa tehdä tämä.

neau33 [19.10.2008 15:39:10]

#

Heippa taas vesimies!

Ideana tuossa "Inherits Form"-kohdassa oli sellainen, että säätelin hieman SharpDevelop'n templaatteja ja editori pukkaa sen oletuksena suoraan formille uuden projektin avaamisen yhteydessä, enkä huomannut sitä erikseen poistaa...

..ja sitten takaisin TekstiBoxi-ongelmaan, eli siis...

'...

Sub TextBox1_KeyDown(sender As Object, _
e As KeyEventArgs) Handles TextBox1.KeyDown
  TsekaaTila(sender, e)
End Sub

Public Sub TsekkaaTila(ByVal ctl As TextBox, ByVal args As KeyEventArgs)
  If Not ctl.Multiline And _
  args.KeyCode = Keys.Enter Then
    MyDefaultButton.PerformClick
  End If
End Sub

vesimies [19.10.2008 16:11:21]

#

Multiline oli hyvä huomio. Ja tosiaan, KeyPress on tässä turha, jäljittelin vain liiaksi ohjeiden esimerkkiä (ks. ohjeista aihe Control.KeyPress Event). Nyt on tällainen toimiva versio:

Private Sub frmTestiLomake_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
    Dim nappiin As Boolean = False
    Dim tekstiruutu As TextBox
    If e.KeyCode = Keys.Enter Then
        nappiin = True
        ' Katsotaan mikä on aktiivinen kontrolli,
        ' ja jos tekstiruutu niin
        ' tutkitaan Multiline:
        If Me.ActiveControl.GetType Is txtSyöttöLuku.GetType Then
            ' Miten tyyppi katsotaan tyylikkäämmin?
            tekstiruutu = Me.ActiveControl
            nappiin = Not tekstiruutu.Multiline
        End If
    End If
    If nappiin Then btnKerro.PerformClick()
End Sub

neau33 [19.10.2008 16:45:30]

#

Heippa taas vesimies!

vielä ehkä hitunen lisää dynaamisuuttaa...

Private Sub frmTestiLomake_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
  If e.KeyCode = Keys.Enter Then
    If Me.ActiveControl.GetType.ToString _
    = "System.Windows.Forms.TextBox" Then
      Dim ctl As TextBox = Me.ActiveControl
      If Not ctl.Multiline Then _
      MyDefaultButton.PerformClick
    Else
      MyDefaultButton.PerformClick
    End If
  End If
End Sub

vesimies [19.10.2008 17:05:19]

#

Kiitos taas. Jotenkin tuntuu hassulta tehdä valintarakenne vertaamalla pitkää tyyppinimi-Stringiä, mutta kaipa siihen tottuu.

Hei mutta nytpä löysin sen ohjeista! Himputti! Turhaan väkersin! Nimittäin:

"On any Windows Form, you can designate a Button control to be the accept button, also known as the default button." ::)

Eli lomakkeen accept buttoniksi vaan se haluttu.

No tulipahan ihan hyviä ohjelmointiharjoituksia näppäinkäsittelyistä.

neau33 [19.10.2008 17:58:01]

#

Heippa taas vesimies!

AcceptButton on näppärä paitsi...Jos haluaa rivinvaihdon toimivan Enter-näppäimellä fromin multiline-boxeissa niin MyDefaultButton toimii edelleen..."MultilineBoxin" yhteydessä voi asettaa ehdon vaikkapa Control-näppäimelle sallimaan MyDefaultButton_Click-tapahtuman painettaessa Enter-näppäintä...

Private Sub frmTestiLomake_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown

  If e.KeyCode = Keys.Enter Then
    If Me.ActiveControl.GetType. _
    ToString.IndexOf("xtBo") > -1 Then
      Dim ctl As TextBox = Me.ActiveControl
      If Not ctl.Multiline
        MyDefaultButton.PerformClick
      ElseIf ctl.Multiline And e.Control Then
        ctl.Tag = ctl.Text
        MyDefaultButton.PerformClick
        ctl.Text = ctl.Tag
        ctl.SelectionStart = ctl.Text.Length
        ctl.SelectionLength = 0
      End If
    Else
      MyDefaultButton.PerformClick
    End If
  End If

End Sub

vesimies [19.10.2008 21:45:50]

#

neau33 kirjoitti:

...GetType.ToString.IndexOf("xtBo") > -1 ...

:D Aika ovelaa!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta