Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB.NET: Visual Basic ja tiedonhaku Access tietokannasta

Ati [28.11.2010 16:26:45]

#

Hei.

Olen tässä tekemässä tietovisaa Visual Basicilla ja tarkoituksena olisi, että ohjelma hakisi Access-tietokannasta kysymyksen ja vastausvaihtoehdot ja tulostaisi ne vastauslomakkeeseen, joka sisältää labelin kysymykselle ja neljä painiketta vastausvaihtoehdoille.

Olen yrittänyt etsiskellä tietoa tästä, mutta pääosa ohjeista on suunnattu enemmän tiedon viemiseksi tietokantoihin, joten jos joku osaisi neuvoa, millaisella koodilla tuo onnistuisi niin kiitos.

neau33 [28.11.2010 19:42:02]

#

Moi Ati!

Onko kyseessä VB.NET vai VB-classic (VB ../4/5/6)?
Elikä jatkossa: jos kyseessä on esim. Visual Basic 6.0 niin liitä aiheen otsikkoon (VB6) ja jos kyseessä on Visual Basic 2002 - 2010 -> lähitulevaisuus) niin liitä aiheen otsikkoon (VB.NET) syystä, että tiedetään missä mennään.

Oletan nyt kuitenkin, että puhut Visual Basic versiosta, joka vaatii .NET Framework alustan.

Malli tietokannasta (MSAccess)

Tietokannan nimi:
Tietovisakanta

Taulut
Nimi: Tietovisataulu

Tietovisataulun kentät
Nimi: kysymys
Asetukset: teksti, perusavain
(kentän indeksi=0)

Nimi: vastaus1
Asetukset: teksti, kentän koko 200

Nimi: vastaus2
Asetukset: teksti, kentän koko 200, arvo tarvitaan

Nimi: vastaus3
Asetukset: teksti, kentän koko 200, arvo tarvitaan

Nimi: vastaus4
Asetukset: teksti, kentän koko 200, arvo tarvitaan


Nimi: oikeavastaus
Asetukset: teksti, kentän koko 200, arvo tarvitaan

Nimi: indksi
Asetukset: luku, pitkä kokonaislukuluku, arvo tarvitaan, indeksoitu
(aloita kentän numerointi 0:sta 0, 1, 2 jne...

VB.NET WindowsForms-projekti:

'Huom! väännetty SharpDevelop 4.0 Beta 4:lla
'(Visual Basic IDE luo oletuksena pääformin nimellä: Form1)

'Lomakkeelle:
'5 Labellia (label1 - label5)

'5 Painiketta (button1 - button5)
'button1.Text="Uusi kysymys"
'button2.Text="Vaihtoehto 1"
'...
'button5.Text="Vaihtoehto 4"

'Aseta kaikki labellit alekkain ja Button1 niiden alle
'loput Buttonit: button2 label2:den viereen jne...

'Tietokannan tulee sijaita samassa kansiossa, jossa
'projektista luotava .exe -tiedosto sijaitsee...
'Designerin debuggerilla ajettaessa: ..\Bin\Debug\
'tai jos julkaistu: ..\Bin\Release

Imports System.Data
Imports System.Data.OleDb

Public Partial Class MainForm

   Private yhteys As OleDbConnection = Nothing
   Private datasetti As DataSet = Nothing
   Private kysymys As Integer = -1
   Private vastaus As String = String.Empty
   Private tietueet As Integer = 0
   Private kysely As String = String.Empty

   Public Sub New()
      Me.InitializeComponent()
   End Sub

   Sub MainForm_Load(sender As Object, e As EventArgs)

      Dim kansioPolku As String = Application.StartupPath
      Dim tiedostoNimi As  String = "Tietovisakanta.mdb"
      'tai "Tietovisa.accdb" jos tietokanta on luotu
      'Access versiolla 12 (Office 2007) -> lähitulevaisuus
      Dim kokoPolku As String = kansioPolku + "\" + tiedostoNimi
      Dim yhteysmerkkijono As String = _
      "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
      + kokoPolku + ";Persist Security Info=False;"
      'asetetaan SQL kyselylause palauttamaan taulun tietueiden lukumäärä
      kysely = _
      "SELECT COUNT(*) As [RecordCount] FROM [Tietovisataulu]"
      yhteys = New OleDbConnection(yhteysmerkkijono)
      yhteys.Open
      Dim komento As New OleDbCommand
      komento.Connection = yhteys
      komento.CommandText = kysely
      'palutetaan SQL kyselyn vastausarvo OleDbCommand-
      'objektin ExecuteScalar-Metodilla ja asetetaan samalla
      'Integer tyyppiin muutettu arvo muuttujan ’tietueet’ arvoksi
      tietueet = CType(komento.ExecuteScalar, Integer)
      yhteys.Close: komento.Dispose

   End Sub

   Sub Button1_Click(sender As Object, e As EventArgs)

      Randomize

      Dim rndkysymys As Integer

      'Jos tietokannasta löytyi tietueita niin
      'arvotaan tietueiden määrästä palautetusta
      'arvosta satunnaisluku 0 - tietueet
      If tietueet > 0 Then
         Do 'pyöritään silmukassa ja arvotaan satunnaislukua
            rndkysymys = CInt(Int(tietueet * Rnd()))
            'jos satunnaisluku ei ole sama, kuin edellisen
            'arvonnan palauttama luku niin...
            If rndkysymys <> kysymys Then
               'asetetaan muuttujan 'kysymys'
               'arvoksi saatu satunnaisluku...
               'ja poistutaan silmukasta
               kysymys = rndkysymys: Exit Do
            End If
         Application.DoEvents: Loop
      End If

      'jos muuttujan kysymys arvo on suurempi kuin -1
      '(nyt edellä arvottu satunnaisluku) niin...

      If kysymys > -1 Then

         'asetetaan SQL-kysely palauttamaan tietue, jonka indeksi-
         'kentän arvo on sama, kuin kysymys (kysymys nro)
         kysely = _
         "Select * From [Tietovisataulu] Where indeksi=" + Cstr(kysymys)
         'luodaan DataSet-objektista uusi ilmentymä ja avataan yhteys
         datasetti = New DataSet: yhteys.Open
         'luodaan uusi ilmentymä OleDbDataAdapter-objektista
         'ja asetetaan sen SQL-kyselylauseeksi merkkijonon 'kysely' arvo
         'ja yhteydeksi OleDbConnection-ilmentymä 'yhteys
         Dim adapteri As New OleDbDataAdapter(kysely, yhteys)
         'täytetään datasetti-objekti adpterin avulla
         adapteri.Fill(datasetti,"Tietovisataulu")
         'tuhotaan adapteri-objekti
         adapteri.Dispose

         'jos datasettiin palautui kyselyn perusteella tietue...
         If datasetti.Tables("Tietovisataulu").Rows.Count > 0 Then
            'niin laskurisilmukan laskuriarvon perusteella...
            For i As Integer = 0 To 5
               Select Case i
                  'tapauksessa että laskuriarvo on pienempi, kuin 5
                  Case Is < 5
                     'asetetaan Formin.Kontrollin(jonka nimi
                     'on "lablel" + merkkijonoksi muutettu'laskuriarvo).
                     Tekstiarvoksi datasetin("Titovisataulun")
                     'datasetin ainoan tietueen (rivin)
                     'laskuriarvoa vastaavan kentän (sarke) arvo
                     Me.Controls("label" & CStr(i + 1)).Text = _
                     CType(datasetti.Tables("Tietovisataulu"). _
                     Rows(0)(i), String)
                  'ja tapauksessa että laskuriarvo on 5

                  Case 5
                     'asetetaan koko tällä lomakkeella
                     'näkyvän muuttujan 'vastaus' arvoksi
                     'datasetin ainoan tietueen 5. kentän arvo,
                     'jonka kentän tulisi sisältää oikea vastaus
                     vastaus = CType(datasetti.Tables( _
                     "Tietovisataulu").Rows(0)(i), String)
               End Select
            Next

         End if

         datasetti = Nothing: kysely = String.Empty

      End If

   End Sub

   Sub Button2_Click(sender As Object, e As EventArgs)
      'Kutsutaan aliohjelmaa ja välitetään kutsussa
      'parametri (tässä tapauksessa ~ "label2")
      VertaaVastausta(2)
   End Sub

   Sub Button3_Click(sender As Object, e As EventArgs)
      VertaaVastausta(3)
   End Sub

   Sub Button4_Click(sender As Object, e As EventArgs)
      VertaaVastausta(4)
   End Sub

   Sub Button5_Click(sender As Object, e As EventArgs)
      VertaaVastausta(5)
   End Sub

   Sub VertaaVastausta(indeksi As Integer)

      'jos vain koko tällä lomakkeella näkyvän
      'muuttujan 'vastaus' arvo on tyhjä merkkijono niin...
      If vastaus = String.Empty Then
         'poistutaan aliohjelmasta
         Exit Sub
      End If

      'jos painettiin oikeaa vaihtehtoa niin..
      If Me.Controls("label" & _
         CStr(indeksi)).Text = vastaus Then
         'näytetään viesti-ikunnassa:
         MsgBox("Oikein vastattu")

      'muussa tapauksessa...
      Else
         'näytetään viesti-ikunnassa:
         MsgBox("Väärin vastattu" & _
         "Oikea vastaus on: " & vastaus)
      End if

      'asetetaan muuttujan 'vastaus' tyhjä mekkijono...
      vastaus = String.Empty

      'ja asetetaan silmukassa kunkin labellin
      'tekstiarvoksi tyhjä mekkijono...
      For i As Integer = 1 To 5
         Me.Controls("label" & _
         CStr(i)).Text = String.Empty
      Next

   End Sub

   Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs)
      yhteys = Nothing
      Me.Dispose
   End Sub

End Class

neau33 [28.11.2010 23:51:41]

#

EDIT:
yllä olevan esimerkin Button1_Click tapahtuman koodista puuttuu...
adapteri.Dispose: yhteys.Close
onnistuin copy/paste-combinoimaan : yhteys.Close pätkän pois

Ati [30.11.2010 15:11:09]

#

Kiitos pikaisesta vastauksesta.

VB.NET on tosiaan käytössä, mutta tuon koodipätkän kanssa oli jonkinlaista häiriötä, kun kokeilin sitä Visual Studio 2010, niin kääntäjä ei alkanut suorittamaan sitä, enkä ole vielä ehtinyt kokeilemaan johtuiko se jostain omasta virheestä.

Ja miten tuon koodin saisi muutettua siten, että tarkoituksena olisi, että vastausvaihtoehtojen tekstit tulostuvat painikkeisiin ja vain kysymys labeliin ja aina käyttäjän vastattua oikein, lomakkeelle päivittyisi uusi kysymys ilman msgboxeja.

Kiitos.

neau33 [30.11.2010 19:23:06]

#

Morjens taas Ati!

Aluksi: Jos koodi ei käänny tai toimi, niin on SATAVARMAA, että se johtuu omasta mokastasi...

tässä, kuitenkin ehdotus kaipamaasi muutokseen...uusi kysymys päivittyy automaattisesti vastauksen ja vastaustuloksen jälkeen (en näe järkeä siinä, että voi vastailla kunnes osuu oikeaan)
Luo uusi Windows Forms-projekti (nimeksi esim. TietovisaTesti)

Tarkista. että Solution Explorer-ikkunassa näkyvässä References-kansiossa näkyy teksti
System.Data, jos ei näy niin klikkaa samaisen kansion kuvaketta hiiren 2-näppimellä ja valitse: Add Reference , valitse .NET välilehti, selaa listalta teksti System.Data, tuplaklikkaa tekstiä ja kilkkaa OK-nappia.

Sijoita lomakkeelle Form1 1 label-objketi (label1) ja 4 komentopainiketta (Button1 - Button4).
Tupklikkaa lomaketta design-tilassa niin koodi-ikkunaan ilmestyy lomakkeen Load tapahtumakoodi:

Private  Sub Form1_Load(sender As Object, e As EventArgs) …
’sijoita aliohjelman koodi tähän…
End Sub

Tuplaklikkaa sitten kutakin painiketta design-tilassa niin koodi-ikkunaan ilmestyy kunkin napin Click tapahtumakoodit:

Private  Sub Button1_Click(sender As Object, e As EventArgs) …
‘sijoita aliohjelman koodi tähän…
End Sub  jne.

Kirjoita sitten koodi-ikkunan alkuun seuraavat Imports-lauseet:

Imports System.Data
Imports System.Data.OleDb

Ja kirjoita koodirivin: Public Class Form1 jälkeen seuraavat objektimuuttujien alustukset

Private yhteys As OleDbConnection = Nothing
Private kysymys As Integer = -1
Private vastaus As String = String.Empty
Private tietueet As Integer = 0
Private kysely As String = String.Empty
Public Shared viesti As String  = String.Empty

Sijoita sitten seuraava koodi Form1_Load tapahtuman koodiksi

Dim kansioPolku As String = Application.StartupPath
Dim tiedostoNimi As  String = "Tietovisakanta.mdb"
Dim kokoPolku As String = kansioPolku + "\" + tiedostoNimi
Dim yhteysmerkkijono As String = _
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
+ kokoPolku + ";Persist Security Info=False;"
kysely = "SELECT COUNT(*) As [RecordCount] FROM [Tietovisataulu]"
yhteys = New OleDbConnection(yhteysmerkkijono)
yhteys.Open
Dim komento As New OleDbCommand
komento.Connection = yhteys
komento.CommandText = kysely
tietueet = CType(komento.ExecuteScalar, Integer)

If tietueet > 0 Then

   kysely="Select * From [Tietovisataulu] Where indeksi=0"
   komento = New OleDbCommand
   komento.Connection = yhteys
   komento.CommandText = kysely
   Dim lukija As OleDbDataReader = komento.ExecuteReader
   If lukija.HasRows Then
      kysymys = 0
        While lukija.Read
            label1.Text = CType(lukija(0), String)
               For i As Integer = 1 to 4
                  Me.Controls("button" & Cstr(i)).Text = CType(lukija(i), String)
               Next
               vastaus =  CType(lukija(5), String)
          End While
      lukija.Close: lukija.Dispose
   End If

End if

yhteys.Close: komento.Dispose

Sijoita sitten seuraava koodi jokaisen komentopainikkeen Click tapahtuman koodiksi:

TarkistaVastaus(sender)

Copy/Paskanna sitten alla oleva koodi johonkin kohtaan From1-luokan sisälle
(ei kuitenkaan toisen aliohjelman sisälle)

Private Sub TarkistaVastaus(sender As Object)

   If CType(sender.Button).Text  = vastaus Then
      viesti = "Vastaus on oikein!"
   Else
      viesti = "Vastaus on väärin!" _
      & Environment.NewLine _
      & "Oikea vastaus on: " & vastaus
   End If

   Dim frm2 As New Form2
   frm2.ShowDialog
   frm2.Dispose
   Randomize

   Dim rndkysymys As Integer

   If tietueet > 0 Then

      Do
         rndkysymys = CInt(Int(tietueet * Rnd()))
        If rndkysymys <> kysymys Then
           kysymys = rndkysymys: Exit Do
        End If
      Application.DoEvents: Loop

   End If

   If kysymys > -1 Then

       kysely = "Select * From [Tietovisataulu] Where indeksi=" + Cstr(kysymys)
       Dim datasetti As New DataSet: yhteys.Open
       Dim adapteri As New OleDbDataAdapter(kysely, yhteys)
       adapteri.Fill(datasetti,"Tietovisataulu")
       adapteri.Dispose: yhteys.Close

      If datasetti.Tables("Tietovisataulu").Rows.Count > 0 Then

         label1.Text = datasetti.Tables("Tietovisataulu"). Rows(0)(0), String)
         For i As Integer = 1 To 4
            Me.Controls("button" & CStr()).Text =  _
            CType(datasetti.Tables("Tietovisataulu").Rows(0)(i), String)
         Next
         vastaus = datasetti.Tables("Tietovisataulu"). Rows(0)(5), String)

      End if

      datasetti = Nothing: kysely = String.Empty

   End If

En Sub

Lisää sitten projektiin uusi tyhjä lomake (Form2) ja lisää lomakkeelle label-objekti (label1)

avaa Form2 koodi-ikkunaan, siirry designer–tilaan ja tuplaklikkaa lomaketta niin koodi-ikkunaan ilmestyy lomakkeen Load tapahtumakoodi:

Private  Sub Form2_Load(sender As Object, e As EventArgs) …
’sijoita aliohjelman koodi tähän…
End Sub

Copy/Pastea alla oleva koodi Form2_Load tapahtuman koodiksi…

Me.FormBorderStyle = FormBorderStyle.None
Me.BackColor = Color.White
Me.Size = New System.Drawing.Size(200, 60)
label1.Size = New System.Drawing.Size(200, 60)
label1.BorderStyle = BorderStyle.FixedSingle
Dim fw As Integer = Me.Width
Dim fh As Integer = Me.Height
Dim sw As Integer = _
Screen.PrimaryScreen.WorkingArea.Width
Dim sh As Integer = _
Screen.PrimaryScreen.WorkingArea.Height
Dim lw As Integer = CType((label1.Width / 2), Integer )
Dim lh As Integer = CType((label1.Height / 2),Integer)
Me.Left = CType((sw / 2) - (fw / 2), Integer)
Me.Top= CType((sh / 2) - (fh / 2), Integer)
label1.AutoSize = True:
label1.Text = MainForm.viesti
label1.Left = CType((fw / 2) - lw, Integer)
label1.Top = CType((fh / 2) - lh, Integer)
Application.DoEvents
System.Threading.Thread.Sleep(2000)
Me.Close

Vastaus

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

Tietoa sivustosta