• No results found

Användargränssnitt

In document Elektroniskt Skyttesystem (Page 27-41)

3 Design

3.5 Databas

3.7.1 Användargränssnitt

används för att lista de beräknade träffresultaten. En mindre Text Box används för att skriva ut det medelvärdesresultat användaren fått från sina träffar. Denna Text Box ska användaren själv ej ha möjlighet att skriva i, så att innehållet endast ändras när medelvärdesresultatet uppdateras utifrån ytterligare träffar.

Visningsklientens användargränssnitt är grafiskt designad i utvecklingsmiljön Visual Studio med hjälp av den designer som subsystemet WPF erbjuder (se Figur 3.6). I denna lösning har man möjlighet att utveckla visningsklientens användargränssnitt genom att skapa och placera komponenter så som knappar, etiketter och boxar av olika slag i designvyn (på engelska

design view) ur en verktygslåda (toolbox). Funktionalitet och egenskaper för dessa

komponenter kan sedan påverkas i ett egenskapsfönster (properties window). Man har även möjlighet att i WPF-lösningar utnyttja något som kallas Extensible Application Markup

Language (XAML) [31], vilket är en XML-baserad språklösning för att initialisera och

definiera objekt i användargränssnittet från en egen ruta (XAML view). En utvecklare kan således skriva kod i XAML-vyn för att påverka en WPF-applikationens visuella utseende utöver det som erbjuds från verktygslådekomponenter och deras egenskaper.

Figur 3.5: Illustration av visningsklientens användargränssnittsdesign

3.7.2 Övergripande bakgrundsfunktionalitet

Visningsklientens bakgrundsfunktionalitet består i huvudsak av fyra klasser (se Figur 3.7):  En kontextklass sätter upp och hanterar kommunikationen med databasen och datan

däri. Denna klass genereras utifrån databasen genom implementation av Entity Framework.

En träffklass innehåller get- och set-metoder till variablerna enhetsID, träffnummer, samt x- och y-position från de respektive kolumner som databasen innehåller. Även denna klass genereras utifrån databasen genom implementation av Entity Framework.  En datahanteringsklass använder instanser av kontextklassen för att koppla

applikationens logik med databasen och dess innehåll. Klassen innehåller metoder för att beräkna träff- och medelvärdesresultat utifrån data i databasen, samt metoder för att hämta ut och skicka vidare denna data.

En vyklass innehåller de metoder som skapar och visualiserar träffcirklar på användargränssnittets träffyta, samt de metoder som skriver ut de olika resultaten i användargränssnittets designerade rutor.

Visningsklientens bakgrundsfunktionalitet utvecklades under projektets gång från en version som förlitade sig mer på kommunikation med databasen genom ramverket Entity Framework för att hantera dess data, till en version som allt mindre förlitade sig på denna kommunikation genom att spara ner all data i databasen och hantera denna mer lokalt. Båda dessa lösningar har fördelar och nackdelar. Den tidigare lösningen funger utmärkt om visningsklienten avser uppdateras för varje individuell träff; det finns då mindre anledning att hämta ner och lägga in allt databasinnehåll i en lista för varje sådan träff. Med denna tidigare lösning så tar datahämtning och beräkning lite längre tid då databasen måste kontaktas flera gånger per träff, men denna fördröjning mellan träff och visualiserat resultat är försumbar för bearbetning av endast en träff åt gången. Om istället flera träffar i följd ska beräknas och visualiseras mellan uppdateringstillfällena så är däremot den senare lösningen mer effektiv, både tidsmässigt och ur kodperspektiv. Flera metoder som krävs i den tidigare lösningen kan refaktoriseras bort ur den senare lösningen eftersom deras funktionalitet kan utföras direkt

Figur 3.7: Illustration av visningsklientens klasser i dess bakgrundsfunktionalitet

3.7.2.1 Ramverksbaserad bakgrundsfunktionalitet

Denna tidigare lösning för visningsklientens bakgrundsfunktionalitet baserade kommunikationen med databasen och dess data utifrån flera metoder innehållande implementation av ramverket Entity Framework. Flera aspekter av denna ramverksbaserade bakgrundsfunktionalitet användes i den fristående testapplikationen (se avsnitt 3.8), som kan simulera träffar för att testa visningsklienten.

En metod i datahanteringsklassen behövde anropas i samband med att applikationen initialiserades med uppgiften att tömma databasen. All data däri behövde tas bort, som försäkring att inga tidigare existerande värden befann sig där som kunde påverka resultatberäkning och träffvisualisering negativt. När så applikationen startas så gör den det med en tom databas och träffyta, och är precis som ett riktigt system redo för en ny träffserie från en användare.

En metod för beräkning av resultat för varje träff krävdes i datahanteringsklassen, som anropades i vyklassen när en uppdatering av användargränssnittet skedde. Detta träffresultat behövdes för de enskilda, beräknade resultaten som skrevs ut i användargränssnittet. I denna metod adderades även det beräknade träffresultatet in i en klassegenskapsvariabel som representerade det totala resultatet för alla träffar i träffserien. Detta totala resultat behövdes sedan när medelresultatet för samtliga träffar beräknades.

För varje enskild träff behövdes dess x- och y-koordinater hämtas ut ur databasen, vilket krävde en metod vardera i datahanteringsklassen för att utföra denna uppgift och returnera koordinaterna de hittade.

När ett träffresultat beräknats i datahanteringsklassen returnerades det ut till vyklassen, som skickade resultatet som en parameter till en metod med uppgiften att skriva ut det i den List Box som befann sig i användargränssnittet. Det totala resultatet skickades som en parameter till en metod som räknade ut det medelresultat som träffserien genererat. Även detta resultat returnerades till vyklassen, för att i en metod skrivas ut i den Text Box som befann sig i användargränssnittet.

En metod i vyklassen skapade en träffellips i användargränssnittets träffyta utifrån en träffs x- och y-koordinater. För att placera träffellipsen rätt på användargränssnittets träffyta behövde dessa koordinater på nytt hämtas ut från databasen genom att anropa de metoder som skötte detta. När träffellipsen fått rätt värden bestämdes dess storlek och färg, och lades sedan till i användargränssnittets träffyta.

Allt detta behövde ske för varje individuell träff i databasen då den anlänt däri. Applikationen måste således kunna uppfatta att en ändring skett i databasen och reagera på detta. Implementation utav sådan funktionalitet visade sig dock vara för tidskrävande; mer om detta i avsnitt 3.7.3.

Härnäst följer en mer ingående beskrivning av först den ramverksbaserade bakgrundsfunktionalitetens vyklassmetoder följt av dess datahanteringsklassmetoder, illustrerade i Figur 3.8 (a respektive b).

(a) (b)

Figur 3.8: Visningsklientens illustrerade vyklassmetoder och ramverksbaserade datahanteringsklassmetoder

visualizeScoreInListBox

Denna metod i vyklassen lade in det beräknade träffresultatet överst i användargränssnittets List Box. Därigenom befann sig alltid det senaste träffresultatet överst i den visualiserade träffserien.

visualizeAverageScoreInTextBox

Denna metod i vyklassen skrev ut det beräknade medelresultatet för alla träffar som en sträng i användargränssnittets Text Box.

visualizeShot

Denna metod i vyklassen skapade träffellipser utifrån de värden som fanns att hämta i databasen. Träffens x- och y-koordinater returnerades till denna metod genom anrop till ett par metoder i datahanteringsklassen med uppgift att hämta ut denna data ur databasen, som därefter tilldelades träffellipsen. När sedan träffellipsens höjd, bredd och färg hade tilldelats antagna värden så kunde träffellipsen till slut läggas till i användargränssnittets träffyta. visualizeAverageShot

Denna metod i vyklassen skapade en träffellips utifrån de övriga träffarna. Träffens x- och y-koordinater returnerades efter att ett par metoder i datahanteringsklassen anropats, vars uppgifter var att beräkna medelvärdet av alla träffars x- respektive y-koordinater. Dessa värden tilldelades sedan träffellipsen, tillsammans med antagna värden för höjd, bredd och färg (denna färg skilde sig från övriga träffar). När detta hade bestämts så kunde träffen till slut läggas till i användargränssnittets träffyta.

clearDB

Denna metod i datahanteringsklassen tog bort alla gamla träffar i databasen, och sparade denna ändring i databasen. Denna metod anropades i samband med att applikationen startades; detta var nödvändigt för att starta visningsklienten tom från gamla skräpvärden som kunde påverka beräkning av träffantal negativt, och gjorde den redo att ta emot nya träffserier från användare.

calculateScore

Denna metod i datahanteringsklassen räknade ut det resultat som den senaste träffen givit. Mittkoordinater för användargränssnittets träffyta i x- och y-led, samt två variabler för deltavärden för x och y definierades. Metoden beräknade det avstånd mellan träffytans mittpunkt i x-led och träffens x-koordinat, samt det avstånd mellan mittpunkten i y-led och

träffens y-koordinat, och tilldelade deltavärdena dessa beräknade avstånd. Avståndet mellan träffen och träffytans mittpunkt kunde beräknas med hjälp av Pythagoras sats utifrån de beräknade deltavärdena:

Avståndet subtraherades sedan från maxresultatet i träffytan (som i detta projekt var tio), vilket gav ett lägre resultat desto längre ifrån träffytans mittpunkt som träffen befann sig. Klassegenskapsvariabeln innehållande totalresultatet för alla träffar adderades med träffens resultat, innan träffresultatet returnerades.

calculateAverageScore

Denna metod i datahanteringsklassen hade i uppgift att beräkna det medelvärde som alla träffar givit. Detta utfördes genom att dividera det totala resultatet för alla träffar med antalet träffar i serien. Det totala resultatet fanns sparat i den klassegenskapsvariabel avsedd för denna uppgift, och antalet träffar hämtades ut ur databasen utifrån den senaste träffens träffnummervärde.

calculateAverageXPosition & calculateAverageYPosition

Dessa metoder i datahanteringsklassen hade i uppgift att beräkna medelvärdet av x- och koordinater hos alla träffar i databasen. För varje träff däri hämtades dess x- respektive y-koordinat ut med hjälp av den get-metod som befann sig i träffklassen, och y-koordinaterna adderades ihop. Metoden returnerade dessa adderade värden dividerat med antalet träffar i databasen, utifrån den klassegenskapsvariabel som höll reda på detta.

getLastShotXPosition & getLastShotYPosition

Dessa metoder i testapplikationens datahanteringsklass hade i uppgift att hämta ut den senaste träffens x- respektive y-koordinat och returnera dem. Eftersom Last-metoden, som har i uppgift att returnera den sista entiteten i en sekvens, inte stöds av Linq-to-Entities-förfrågor så behövde man ordna databasen i nedåtgående ordning och sedan välja ut den första entiteten i denna ordnade sekvens med en First-metod.

funktionalitet för att uppdatera visningsklienten vid databasändringar var för tidskrävande (se avsnitt 3.7.3) behövde ett alternativ tas fram.

En ny lösning togs fram, som hämtar ner alla träffar i databasen och lägger in dessa i en lista varje gång en användarstyrd uppdatering sker. Detta medföljer att värdeshanteringen istället för att vara fullt kopplad med databasen nu sker på lokalt hämtade värden. Träffarna kan direkt skickas utifrån listan som argument till metoder, vilket leder till att deras värden kan hämtas och sättas med hjälp av de definierade get- och set-metoder som finns i träffklassen. Detta ledde till att några metoder kunde refaktoriseras bort då deras funktionalitet effektivare kunde utnyttjas direkt på medskickade objekt och värden. De metoder som visningsklienten består av beskrivs i följande avsnitt, där dess metoder i vyklassen illustrerade i Figur 3.8 (a) följs av de som befinner sig i dess datahanteringsklass (se Figur 3.9).

Figur 3.9: Den listbaserade visningsklientens illustrerade datahanteringsklassmetoder

visualizeScoreInListBox, visualizeAverageInTextBox & visualizeAverageShot

Dessa metoder återfinns i visningsklientens vyklass, och de behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1).

visualizeShot

Denna metod i vyklassen behåller sin tidigare funktionalitet (se avsnitt 3.5.2.1), med några förändringar. En träffparameter tas emot av funktionen, och det är utifrån denna medskickade träff som den visualiserade träffens x- och y-koordinater hämtas och tilldelas.

clearDB

Denna metod i datahanteringsklassen behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1).

loadDBShotsIntoList

Denna metod i datahanteringsklassen skapar en ny instans av listan som träffarna läggs in i. Metoden tilldelar även en träffräknare värdet noll, samt nollställer totalresultatet för träffserien. För varje träff i databasen läggs sedan träffen in i listan, dess värden sätts med hjälp av set-metoderna i träffklassen till de värden som återfinns i databasen, och räknaren inkrementeras. Denna räknare kan sedan användas för att utreda hur många träffar som finns i listan.

calculateScore

Denna metod i datahanteringsklassen behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1), med några förändringar. Som parameter tar den här metoden emot en träff, utifrån vilken de x- och y-koordinater som används vid beräkning hämtas ut ifrån. Denna metod behöver då inte längre uppsöka den senaste träffen i databasen och hämta ut dess x - och y-koordinater, vilket behövdes i den tidigare ramverksbaserade lösningen.

calculateAverageScore

Denna metod i datahanteringsklassen behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1); metoden får dock träffantalet genom den klassegenskapsvariabel med uppgift att hålla reda på detta antal, istället för att som i den tidigare lösningen hämta ut den senaste träffens nummer i träffordningen.

calculateAverageXPosition & calculateAverageYPosition

Dessa metoder i datahanteringsklassen behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1), med några förändringar. Istället för att hämta x- respektive y-koordinater från alla träffar i databasen utförs detta mot alla träffar i listan med hjälp av de get-metoder som befinner sig i träffklassen. Dessa koordinatvärden adderas ihop, och metoderna returnerar dessa värden dividerat med antal träffar i listan, som går att återfinna i den klassegenskapsvariabel med uppgift att hålla reda på detta.

3.7.3 Hämtning av data från databasen

Hämtning av databasdata vore idealisk om denna kunde ske i samband med att varje träff anländer i databasen. För att detta ska vara möjligt så måste databasändringar registreras och

Tekniken SignalR sätter upp ett bakplan (på engelska backplane), som tar emot och vidarebefordrar meddelanden från och till varje applikationsinstans. Varje sådant meddelande skickas genom en meddelandebuss med en publish/subscribe-mekanism designad för bakplanet; serverinstanser kopplas sedan till bakplanet genom denna buss. När meddelanden sedan avses skickas till servern hamnar det istället först i bakplanet, som har möjlighet att skicka vidare meddelandet till alla eventuella serverinstanser. När en server således tar emot ett meddelande från bakplanet placeras det i serverns lokala cache-minne, varifrån meddelanden sedan levereras till klienter [33].

Ett relevant användningsområde med SignalR-implementation att jämföra önskad funktionalitet med är chattapplikationer; en sådan applikation kan utnyttja publish/subscribe-kommunikation mellan två eller flera klientapplikationer genom en serverinstans. Ett meddelande från en klient når och lagras således i databasen, som har möjlighet att publicera att en ändring i dess innehåll har skett. Övriga klienter som prenumererar på relevanta händelser i databasen har då möjlighet att ta emot meddelanden från servern och uppdatera sina användargränssnitt därefter. En snarlik lösning för applikationen i Raspberry-enheten, databasen och visningsklienten hade varit önskvärd, men på grund av projekttidsbrist hann en sådan implementation inte tas fram. Således fick visningsklienten fungera utifrån en alternativ lösning.

I nuläget uppdaterar visningsklienten istället sitt användargränssnitt med hämtad databasdata utifrån manuell uppdatering. Genom att en användare trycker på en knapp i användargränssnittet så hämtas all databasdata till visningsklienten och läggs in i en lista. De funktioner som sedan behöver denna data för beräkning och visualisering kommunicerar följaktligen med denna lokala lista.

Detta möjliggör beräkning och visualisering av flera träffar i följd. Med den ramverksbaserade lösningen var sådan följduppdatering möjlig, men den krävde upprepad kommunikation med molndatabasen för att hämta x- och y-koordinater för varje träff, samt för att returnera den sista träffens nummer i träffordningen; detta var nödvändigt för att veta hur många träffar som behövde beräknas och visualiseras. Eftersom åtkomst till databasen är skild från vyklassen måste således flera metoder i datahanteringsklassen med möjlighet att hämta databasdata anropas därifrån så att relevanta värden kan returneras.

3.8 Träffsimulering

För att kunna visualisera träffar och beräknade värden i visningsklienten behöver data som ska hämtas ur databasen faktiskt finnas där. En fristående testapplikation togs därför fram för att simulera träffar så att funktionaliteten kring dem kan testas i visningsklienten. Testapplikationens syfte är därmed att skapa de databasentiteter som visningsklienten sedan kan hämta genom manuell användaruppdatering.

Testapplikationen liknar visningsklienten, både i användargränssnitt och bakgrundsfunktionalitet (se Figur 3.10). Den skiljer sig dock i att en användare med hjälp av muspekaren kan skapa träffar i användargränssnittets träffyta; för att tydliggöra detta skiftar muspekarikonen till ett kors när denna befinner sig inom träffytan. För varje träff som skapas skickas dess värden in i databasen, där de sedan hämtas tillbaka för att beräknas och visualiseras. Denna händelsekedja visar att inlägg och uthämtning av data i och ur databasen är möjlig och fungerar korrekt.

Testapplikationen motsvarar den tidigare ramverksbaserade visningsklientlösningen. Eftersom uppdateringen i testapplikationen sker för varje träff så ansågs det inte finnas någon anledning att hämta ner alla databasvärden i en lista varje gång uppdateringen sker; testapplikationen arbetar således direkt mot databasen. Testapplikationen blir då lite långsammare, särskilt om en serie träffar simuleras i snabb följd, men eftersom applikationen är fristående från visningsklienten och endast avsedd för träffsimulering i brist på riktiga värden ansågs detta försumbart.

Den ytterligare funktionalitet som skiljer testapplikationen åt från visningsklienten är att varje uppdatering sker när en användare trycker ner vänster musknapp då muspekaren befinner sig inom användargränssnittets träffyta. När en träff skapas däri sätts träffens x- och y-koordinater till de y-koordinater som muspekaren har vid träfftillfället; varje träff som simuleras skickas in i databasen med dessa värden samt enhetsidentitet och ett träffnummer enligt en räknare av antalet simulerade träffar. Eftersom testapplikationen precis som den ramverksbaserade visningsklienten räknar ut träffresultat för varje träff när den simuleras så behöver den möjlighet att hämta ut x- och y-koordinater för den senaste träffen, och därför återfinns två sådana metoder.

Figur 3.10: Illustration av visningsklient, testapplikation och databas

3.8.1 Testapplikationens vyklass

Testapplikationens vyklass har, precis som visningsklientens sådan, i uppgift att visualisera träffar och beräknade resultat. Skillnaden här är att användaren själv väljer var i användargränssnittets träffyta som träffarna placeras, genom att med muspekaren klicka inom träffytan. Dessa användarplacerade träffar ämnas sedan skickas in i databasen, med de koordinater och träffnummer som träffsimuleringen genererar.

Härnäst beskrivs testapplikationens vyklassmetoder.

3.8.1.1 visualizeScoreInListBox & visualizeAverageInTextBox

Dessa metoder i testapplikationens vyklass behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1).

3.8.1.2 createAndVisualizeShot

Denna metod i testapplikationens vyklass skapar och visualiserar de simulerade träffarna i sitt gränssnitt. Träffarnas x- och y-koordinater sätts till de värden som muspekarens position har

vid träfftillfället. En räknare i datahanteringsklassen inkrementeras varje gång en träff läggs till i användargränssnittet, för att hålla reda på det antal träffar som simuleras. Efter detta så skickas träffens x- och y-koordinater som argument i ett anrop till en metod i datahanteringsklassen som lägger till träffen i databasen.

3.8.2 Testapplikationens datahanteringsklass

Testapplikationens datahanteringsklass, liknande den datahanteringsklass som finns i visningsklienten, har i uppgift att tömma databasen, lägga till träffar i den, hämta ut nödvändiga värden utifrån den data däri och beräkna träffresultat.

Härnäst beskrivs datahanteringsklassens metoder.

3.8.2.1 clearDB

Denna metod i testapplikationens datahanteringsklass behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1).

3.8.2.2 insertShotIntoDB

Denna metod i testapplikationens datahanteringsklass har i uppgift att lägga till en träffentitet i databasen. Den tar emot träffens x- och y-koordinater som parametrar, och lägger till en träff med dessa värden samt en antagen enhetsidentitet med värdet ett och träffnummer enligt den räknare som inkrementeras när träffar simuleras i användargränssnittets träffyta. När en träff således har lagts in i databasen så sparas denna ändring.

3.8.2.3 getLastShotXPosition & getLastShotYPosition

Dessa metoder i testapplikationens datahanteringsklass behåller den funktionalitet som tidigare beskrivits (se respektive metoder i avsnitt 3.7.2.1).

3.8.2.4 calculateScore

3.8.2.5 calculateAverageScore

Denna metod i testapplikationens datahanteringsklass behåller den funktionalitet som tidigare beskrivits (se avsnitt 3.5.2.1); de värden som divideras är totalresultatet för alla träffar samt antal träffar i databasen. Båda dessa värden återfinns i klassegenskapsvariabler i

In document Elektroniskt Skyttesystem (Page 27-41)

Related documents