Pieniä kysymyksiä ohjelmoinnista

Koodi:
var row = document.getElementById('tableRowElement');
row.parentNode.appendChild(row);

tuosta pikku vinkki.

Vinkilläsi pääsin niin pitkälle että nyt raidoitus toimii filteröinnin kera. Mutta nyt ongelmaksi muodostui piilotettujen alkioiden palauttaminen kun filteristä poistaa kirjaimia. Joku pikkuvirhe tuossa ilmeisesti on :btooth:

Edit: Siis filteröinti toimii mutta jos pyyhin filtterin input kentästä kaiken tekstin pois pitäisi näkyä koko lista mutta jostain syystä häviää kaikki alkiot listasta :itku:
Koodi:
<input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">

$(function(){
// save all list entries to global variable trs
    table = document.getElementById("myTableBody");
    trs = table.getElementsByTagName("tr");
});

function myFunction(list) {
// Declare variables
    var input, filter, td, i, rows = [];
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    tr = list;


// Loop through all table rows, and hide those who don't match the search query
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[1];
        if (td) {
            if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
                rows.push(tr[i]);
            }
        }
    }

    $("#myTableBody").empty();

// if filter is longer than 0 characters build list with filtered items only, if not display the original list
    if (filter.length > 0) {
        for (i = 0; i < rows.length; i++){
            $("#myTableBody").append(rows[i]);
        }
    } else {
        for (i = 0; i < tr.length; i++) {
            $("#myTableBody").append(tr[i]);
        }
    }
}
 
Viimeksi muokattu:
Vinkilläsi pääsin niin pitkälle että nyt raidoitus toimii filteröinnin kera. Mutta nyt ongelmaksi muodostui piilotettujen alkioiden palauttaminen kun filteristä poistaa kirjaimia. Joku pikkuvirhe tuossa ilmeisesti on :btooth:

Edit: Siis filteröinti toimii mutta jos pyyhin filtterin input kentästä kaiken tekstin pois pitäisi näkyä koko lista mutta jostain syystä häviää kaikki alkiot listasta :itku:
Koodi:
<input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">

$(function(){
// save all list entries to global variable trs
    table = document.getElementById("myTableBody");
    trs = table.getElementsByTagName("tr");
});

function myFunction(list) {
// Declare variables
    var input, filter, td, i, rows = [];
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    tr = list;


// Loop through all table rows, and hide those who don't match the search query
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[1];
        if (td) {
            if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
                rows.push(tr[i]);
            }
        }
    }

    $("#myTableBody").empty();

// if filter is longer than 0 characters build list with filtered items only, if not display the original list
    if (filter.length > 0) {
        for (i = 0; i < rows.length; i++){
            $("#myTableBody").append(rows[i]);
        }
    } else {
        for (i = 0; i < tr.length; i++) {
            $("#myTableBody").append(tr[i]);
        }
    }
}
Käytä vikassa elsessä kun haku on 0merkkinen trs muuttujaa tr:n sijaan?
 
Ne ls-listan sisältämät listat on suunnilleen tällaisia:
Koodi:
['0001603269', 'XX', '12', '07:50', '12:35', '13:20', '17:05']
['0001603269', 'XX', '13', '07:51', '12:34', '13:23', '17:04']
['0001603269', 'XX', '14', '07:53', '12:33', '13:23', '17:25']
['0001603269', 'XX', '15', '07:51', '12:33', '13:23', '17:05']
['0001603269', 'XX', '16', '07:47', '12:33', '13:23', '17:04']
.

Kannattaa näissä myös kertoa, mitä olet tekemässä. Tuollainen lista erityyppisiä arvoja ei välttämättä ole lainkaan järkevin tapa esittää sitä dataa ja prosessoida sitä. Koodia katsomalla ei kellekään oikein aukene, mitä listan eri elementit oikein ovat. Ja näin virheiden löytäminenkin voi vaikeutua.
 
Käytä vikassa elsessä kun haku on 0merkkinen trs muuttujaa tr:n sijaan?
Koodi:
$(function(){
// save all list entries to global variable trs
   table = document.getElementById("myTableBody");
    trs = table.getElementsByTagName("tr");
});
Ellen väärin käsittänyt tuo luo globaalin muuttujan trs joka sisältää kaikki ladatun sivun tablen tr elementit.

Koodi:
<input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">
Tämä taas kutsuu funktion ja passaa sille parametreinä tuon trs listan.

Koodi:
function myFunction(list) {
// Declare variables
   var input, filter, td, i, rows = [];
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    tr = list;
Tämä taas antaa passatulle lista parametrille nimen tr. Eikö tässä tapauksessa trs == tr ?
 
Koodi:
$(function(){
// save all list entries to global variable trs
   table = document.getElementById("myTableBody");
    trs = table.getElementsByTagName("tr");
});
Ellen väärin käsittänyt tuo luo globaalin muuttujan trs joka sisältää kaikki ladatun sivun tablen tr elementit.

Koodi:
<input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">
Tämä taas kutsuu funktion ja passaa sille parametreinä tuon trs listan.

Koodi:
function myFunction(list) {
// Declare variables
   var input, filter, td, i, rows = [];
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    tr = list;
Tämä taas antaa passatulle lista parametrille nimen tr. Eikö tässä tapauksessa trs == tr ?
Puuh, kännykän näyttö ei vissiin oo paras yrittää selailla koodia. Eli ohjeeni oli vähän turha.
 
For checking if a string is empty, null or undefined I use:
Koodi:
function isEmpty(str) {
   return (!str || 0 === str.length);
}
For checking if a string is blank, null or undefined I use:

Koodi:
function isBlank(str) {
   return (!str || /^\s*$/.test(str));
}
For checking if a string is blank or contains only white-space:

Koodi:
String.prototype.isEmpty = function() {
   return (this.length === 0 || !this.trim());
};

Stackoverflowsta löysin nuo kun aloin miettimään että siinä saatta jostain syystä olla joku näkymätön merkki ja sen pituus on silloin erisuuri kuin nolla. Eli kaksi viimeistä olisi tässä parempia, tai siis toinen niistä.
 
Ellen väärin käsittänyt tuo luo globaalin muuttujan trs joka sisältää kaikki ladatun sivun tablen tr elementit.

Tuosta pitäis ottaa "syvä" kopio. Nyt tässä kopioidaan käytännössä vain viittaus tuohon elementtiin.

eli
Koodi:
$("#myTableBody").empty();
on sama asia kuin kirjoittasit suoraan
Koodi:
table,trs = null


Paatonne init/default funktioon jotain tällästä.
Koodi:
savedTable = $("#myTableBody").clone();
ja vikaan elseen
Koodi:
$("#myTableBody").html(savedTable)
tai jotain muuta vastaavaa.
 
Tuosta pitäis ottaa "syvä" kopio. Nyt tässä kopioidaan käytännössä vain viittaus tuohon elementtiin.

eli
Koodi:
$("#myTableBody").empty();
on sama asia kuin kirjoittasit suoraan
Koodi:
table,trs = null


Paatonne init/default funktioon jotain tällästä.
Koodi:
savedTable = $("#myTableBody").clone();
ja vikaan elseen
Koodi:
$("#myTableBody").html(savedTable)
tai jotain muuta vastaavaa.


Ehh..

Katotaan jos kohta pääsen koneelle nii kerron jotain järkevämpää. :D tuo yllä on aika purkkapantentti tai ainaki alko tuntuu siltä.
 
Koodi:
$(function(){
// save all list entries to global variable trs
   table = document.getElementById("myTableBody");
    trs = table.getElementsByTagName("tr");
});
Ellen väärin käsittänyt tuo luo globaalin muuttujan trs joka sisältää kaikki ladatun sivun tablen tr elementit.

Koodi:
<input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">
Tämä taas kutsuu funktion ja passaa sille parametreinä tuon trs listan.

Koodi:
function myFunction(list) {
// Declare variables
   var input, filter, td, i, rows = [];
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    tr = list;
Tämä taas antaa passatulle lista parametrille nimen tr. Eikö tässä tapauksessa trs == tr ?

Tuolla kloonauksella kuten nnaku tuossa ehdotti.
Tulipahan opittu itsekin tässä jotain uutta. :lol:

Tällaisella virityksellä näyttäis toimivan:
kommentoin siitä tuon korvattavan pois.
Koodi:
$(document).ready(function(){
  console.log("loaded once");
// save all list entries to global variable trs
    table = document.getElementById("myTableBody");
    trs = $("tr").clone()
    //trs = table.getElementsByTagName("tr");
    console.log(trs);
});
Tryit Editor v3.5

edit: hups, tonne tryit editoriin jäi vähän turhan paljon console.logia ja vaikka mitä turhaa.
 
Kannattaa näissä myös kertoa, mitä olet tekemässä. Tuollainen lista erityyppisiä arvoja ei välttämättä ole lainkaan järkevin tapa esittää sitä dataa ja prosessoida sitä. Koodia katsomalla ei kellekään oikein aukene, mitä listan eri elementit oikein ovat. Ja näin virheiden löytäminenkin voi vaikeutua.
Värkkään ohjelmaa, joka hakee tekstitiedostoista työaikaleimaustietoja. Tuossa listassa näkyy siistityssä muodossa työntekijän XX leimauksia viideltä eri päivältä. Listassa on seuraavat tiedot:
  • RFID-kortin tunnusnumero
  • Nimi
  • Leimauspäivä
  • Päivän ensimmäinen sisäänleimaus
  • Päivän ensimmäinen ulosleimaus
  • Päivän toinen sisäänleimaus
  • Päivän toinen ulosleimaus
Kaikki kentät on string-muotoisia.

Tällä hetkellä saan nuo listat ulos .csv:nä, mutta tarkoitus olisi tehdä tietokanta (sqlite) ja joku graafinen käyttöliittymä.
 
Tuolla kloonauksella kuten nnaku tuossa ehdotti.
Tulipahan opittu itsekin tässä jotain uutta. :lol:

Tällaisella virityksellä näyttäis toimivan:
kommentoin siitä tuon korvattavan pois.
Koodi:
$(document).ready(function(){
  console.log("loaded once");
// save all list entries to global variable trs
    table = document.getElementById("myTableBody");
    trs = $("tr").clone()
    //trs = table.getElementsByTagName("tr");
    console.log(trs);
});
Tryit Editor v3.5

edit: hups, tonne tryit editoriin jäi vähän turhan paljon console.logia ja vaikka mitä turhaa.

@Dradge
Itse en lähtis ehkä sittenkään kloonailemaan mitään. Vaan ihan kiltisti piilottelisin ne kentät.

jQuery addClass example - JSFiddle

edit:
Muistelin että joskus tutkin vähän asiaa ja toi jQuery pätkä tuli joskus jossain vastaan ja sattu vielä löytyy koneelta. :)
 
Viimeksi muokattu:
Tuosta pitäis ottaa "syvä" kopio. Nyt tässä kopioidaan käytännössä vain viittaus tuohon elementtiin.

eli
Koodi:
$("#myTableBody").empty();
on sama asia kuin kirjoittasit suoraan
Koodi:
table,trs = null


Paatonne init/default funktioon jotain tällästä.
Koodi:
savedTable = $("#myTableBody").clone();
ja vikaan elseen
Koodi:
$("#myTableBody").html(savedTable)
tai jotain muuta vastaavaa.

Jostain syystä ei riittänyt tuon tablen cloonaus vaan piti käyttää muuttujaa trs = $("#myTableBody tr").clone(); :eek: Mutta nappiin meni syvän kopion suhteen kuitenkin ja sitä kautta ongelmaan kiinni :tup:

Tuolla kloonauksella kuten nnaku tuossa ehdotti.
Tulipahan opittu itsekin tässä jotain uutta. :lol:

Tällaisella virityksellä näyttäis toimivan:
kommentoin siitä tuon korvattavan pois.
Koodi:
$(document).ready(function(){
  console.log("loaded once");
// save all list entries to global variable trs
    table = document.getElementById("myTableBody");
    trs = $("tr").clone()
    //trs = table.getElementsByTagName("tr");
    console.log(trs);
});
Tryit Editor v3.5

edit: hups, tonne tryit editoriin jäi vähän turhan paljon console.logia ja vaikka mitä turhaa.

trs = $("tr").clone() nappasi listaan myös <tr> tagien sisällä olevan taulukon headerin. Siksi trs = $("#myTableBody tr").clone();
Koodi:
$(function(){
});
On vain lyhyempi kirjoittaa kuin
Koodi:
$(document).ready(function(){
});
Ajavat saman asian ;)
jQuery Syntax

Kiitokset kaikille vastauksistanne sekä ajastanne :happy:

Lopuksi vielä tuo toimiva django html template kokonaisuudessaan :cigar2:
Koodi:
{% extends "base_generic.html" %}

{% block content %}
    <div class="d-flex">
        <div class="flex-fill">
            <br>
            <input class="form-control" onkeyup="myFunction(trs)" id="myInput" type="text" placeholder="Etsi piirustusnumerolla.">
            <br>
            <table id="myTable" class="table table-condensed table-striped">
                <thead>
                <tr>
                    <th>Kappale</th>
                    <th>Piirustus numero</th>
                    <th>Varastossa</th>
                </tr>
                </thead>
                <tbody id="myTableBody">
                {% for workPiece in object_list %}
                    <tr>
                        <td><a href="{{ workPiece.get_absolute_update_url }}">{{ workPiece.name }}</td>
                        <td>{{ workPiece.drawingNumber }}</td>
                        <td>{{ workPiece.workPiecesInStock }}</td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
{% endblock %}

{% block script %}
    document.getElementById("btn3").className = "btn btn-primary w-100 active";

    $(function(){
        trs = $("#myTableBody tr").clone();
    });

    function myFunction(list) {
    // Declare variables
        var input, filter, td, tr, i, rows = [];
        input = document.getElementById("myInput");
        filter = input.value.toUpperCase();
        tr = list;


    // Loop through all table rows, and hide those who don't match the search query
        for (i = 0; i < tr.length; i++) {
            td = tr[i].getElementsByTagName("td")[1];
            if (td) {
                if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
                    rows.push(tr[i]);
                }
            }
        }

        $("#myTableBody").empty();

        if (filter != "") {
            for (i = 0; i < rows.length; i++){
                $("#myTableBody").append(rows[i]);
            }
        } else {
            // for (i = 0; i < tr.length; i++) {
                // $("#myTableBody").append(tr[i]);
            // }
            $("#myTableBody").append(tr);
        }
    }
{% endblock %}

E: else lauseen vaihdoin vielä vähän suorituskykyisempään:confused: tai ainakin luettavampaan $("#myTableBody").append(tr); muotoon :btooth:
 
Viimeksi muokattu:
@Dradge
Itse en lähtis ehkä sittenkään kloonailemaan mitään. Vaan ihan kiltisti piilottelisin ne kentät.
Jep. Aika kauhea purkka tuo kloonaushimmeli. Tuohon kun kuitenkin riittäisi yksi filtteröinti-looppi, joka piilottaisi rivin jos se ei mätsää hakuun TAI jos mätsää, muuttaisi rivin tyylin oikeaksi.
 
Jep. Aika kauhea purkka tuo kloonaushimmeli. Tuohon kun kuitenkin riittäisi yksi filtteröinti-looppi, joka piilottaisi rivin jos se ei mätsää hakuun TAI jos mätsää, muuttaisi rivin tyylin oikeaksi.

Muttakun samalla haluttiin nth-child(odd) seepra taulukko. Joka nappaa myös piilotetut kentän... :beye: Niin piti vähän muutakin askarrella
 
Muttakun samalla haluttiin nth-child(odd) seepra taulukko. Joka nappaa myös piilotetut kentän... :beye: Niin piti vähän muutakin askarrella

Itse olisin ollut laiska, piilottanut kaikki by default. Mikäli filtteri osuu, lisännyt luokan mallia "foobar" tms, jonka kanssa sitten td.foobar:nth-child(odd)
 
JavaScriptille (node) design pattern hakusessa. Tarkotus olis muokata tiedosta servulla synkronoidusti, niin että muut odottaa kunnes edellinen on lukenut, editoinut ja kirjoittanut tiedoston.

ideoita?
 
JavaScriptille (node) design pattern hakusessa. Tarkotus olis muokata tiedosta servulla synkronoidusti, niin että muut odottaa kunnes edellinen on lukenut, editoinut ja kirjoittanut tiedoston.

ideoita?
Joku flagi tietokantaan/fileen? keskeneräisen jobin statuksesta?
 
JavaScriptille (node) design pattern hakusessa. Tarkotus olis muokata tiedosta servulla synkronoidusti, niin että muut odottaa kunnes edellinen on lukenut, editoinut ja kirjoittanut tiedoston.

ideoita?

Eikö Node fs:n sync read ja write ja riitä tuohon?
 
Liekö oikea ketju, mutta kysytään nyt kuitenkin. Pitäisi tehdä eräs SQL/Tietokanta tehtävä, joka tuottaa itselleni aika paljon vaikeuksia, koska aikaisempaa kokemusta noista ei oikein ole.

Tehtävä kuuluu näin

Suunnittele kantarakenne kuvattuun tilanteeseen
- Normalisoi kantarakenne
- Huomioi viite-eheys, kirjoita auki tai merkitse viite-eheyssäännöt
- Toteuta esimerkkikyselyt ja kerro niiden käytöstä, esim. mitä muutoksia hakuun pitää tehdä, jotta voidaan toteuttaa vastaava haku eri parametreilla.

Pieni yritys tarvitsee www-sivuilleen tilausjärjestelmän, jossa sivuilla vierailevat henkilöt voivat tilata joitain yrityksen tuotteita. Tuotteilla on niiden myyntinimi, kuvaus ja hinta ja varastosaldo. Asiakkaasta yritys haluaa tallentaa järjestelmään asiakkaan yhteystiedot tilauksen tuotteiden toimittamista varten. Lisäksi he haluavat helposti nähdä kunkin tilauksen tuotteet. He haluavat pystyä merkitsemään käsitellyt tilaukset, jotta he tietävät mitkä tilaukset on jo lähetetty. Asiakas voi tilata yhtä tuotetta myös useammankin kappaleen. Varastosaldoa ei tarvitse päivittää, jos tilauksia lisätään kantaan.

Esimerkkikyselyt:

- Tilauksen tuotteiden haku tilausnumeron perusteella
- Tilauksen tilaajan tietojen haku
- Kaikkien tilausten kokonaissummien haku aikajärjestyksessä
- Asiakasrekisterin haku (eri asiakkaat yhteystietoineen)
- Eri tuotteiden varastosaldo - Tuotekohtaiset tilausmäärät

Työkaluina toimii MySQL Workbench ja phpMyAdmin. Taulujen tekeminen phpMyAdminilla onnistuu joten kuten, mutta tuosta eteenpäin sanoo eioota. Elikkä kaipaisin ohjeistusta, mallia tms. mikä auttaisi tämän tehtävän tekemisessä. Voi vastata esim. YV:llä.
 
Liekö oikea ketju, mutta kysytään nyt kuitenkin. Pitäisi tehdä eräs SQL/Tietokanta tehtävä, joka tuottaa itselleni aika paljon vaikeuksia, koska aikaisempaa kokemusta noista ei oikein ole.

Kannattaa opiskella SQL:n perusteet hyvin, koska tätä tarvitsee joka paikassa. Oletko skipannut pari tuntia, kun mennään suoraan suunnitteluvaiheeseen ja monimutkaisiin liitoksiin jos kerta just ja just osaat tehdä taulun?

Kirjoittelin nyt kuitenkin vähän mistä kulmasta itse lähtisin tätä avaamaan. Koodia ei ole testattu, eikä kaikista käyttötapauksia löydy SQL-kyselyitä, mutta tällä varmaan pääsee liikenteeseen.

Koodi:
-- tuotteet
products
id: int (pk), name: varchar, description: text, price: float

-- inventaario / varaston saldo
inventory
id: int (pk), units: int, product_id: int (fk)

-- asiakkaat (tilaajat) ja heidän yhteystiedot
customers
id: int (pk), first_name: varchar, last_name: varchar, address: varchar, city: varchar, postal_code: varchar, country: varchar

-- tilaukset ja tilausnumero, fk-viittaus asiakkaaseen, oletetaan että tilaus käsitellään kokonaisuutena jolloin shipped vaihdetaan true arvoon kun kaikki tilauksen tuotteet on lähetetty
orders
id: int (pk), customer_id: int (fk), shipped: bit, order_date: datetime

-- tilauksessa olevat tuotteet, fk-viittaukset tilaukseen ja tuotteisiin. Mikäli tilauksessa on esim. viisi _eri_ tuotetta niin tähän tauluun tulee 5 riviä. Mikäli tilataan samaa tuotetta 5 kpl tulee tauluun yksi rivi, mutta  units-kenttään tulee 5
order_products
id: int (pk), order_id: int (fk), product_id: int (fk), units: int

-- Tilauksen tuotteiden haku tilausnumeron perusteella
SELECT
    products.id,
    products.name,
    products.description,
    products.price
FROM orders
JOIN order_products ON orders.id = order_products.order_id
JOIN products ON products.id = order_products.product_id
WHERE orders.id = ?;

-- Tilauksen tilaajan tietojen haku
SELECT
    customers.first_name,
    customers.last_name,
    customers.address,
    customers.city,
    customers.postal_code,
    customers.country
FROM customers
JOIN orders on customers.id = orders.customer_id
WHERE orders.id = ?;
 
Viimeksi muokattu:
Värkkään ohjelmaa, joka hakee tekstitiedostoista työaikaleimaustietoja. Tuossa listassa näkyy siistityssä muodossa työntekijän XX leimauksia viideltä eri päivältä. Listassa on seuraavat tiedot:
  • RFID-kortin tunnusnumero
  • Nimi
  • Leimauspäivä
  • Päivän ensimmäinen sisäänleimaus
  • Päivän ensimmäinen ulosleimaus
  • Päivän toinen sisäänleimaus
  • Päivän toinen ulosleimaus
Kaikki kentät on string-muotoisia.

Tällä hetkellä saan nuo listat ulos .csv:nä, mutta tarkoitus olisi tehdä tietokanta (sqlite) ja joku graafinen käyttöliittymä.
Tämän viime viestin jälkeen suurin osa projektiin käytetystä ajasta on mennyt vielä tuon listan siivouksen hoitavan funktion fiksailuun, mutta sain nyt tehtä myös funktion, joka siirtää tiedot sqlite-tietokantaan. Tästä vaiheesta tulikin mieleen yksi kysymys.

Funktio luo kaksi taulukkoa (gen_data ja badge_data). Gen_datassa on kuukausikohtaiset tiedot ja badge_datassa päiväkohtaiset tiedot. Haluaisin sitoa month_id-kentän export_id-kenttään siten, että badge_data-taulukkoon ei saisi lisättyä sellaista riviä, jonka month_id ei vastaa jotain gen_data-taulussa olevaa export_id:tä. Onko tällaisen ominaisuuden lisääminen vaikeaa?

Koodi:
def db_writer(input_data: tuple):

    gen_data, badge_data = input_data[0], input_data[1]

    db = sqlite3.connect('wh_db.sqlite')

    c = db.cursor()

    c.execute("CREATE TABLE IF NOT EXISTS gen_data"
              "(export_id INTEGER PRIMARY KEY, export_date TEXT, "
              "export_time TEXT, from_date TEXT, to_date TEXT)")

    c.execute("CREATE TABLE IF NOT EXISTS badge_data"
              "(day_id INTEGER PRIMARY KEY, badge_id TEXT, name TEXT, date TEXT, first_entry TEXT, first_exit TEXT, "
              "second_entry TEXT, second_exit TEXT, month_id)")

    record_exists = c.execute("SELECT export_date, export_time FROM gen_data WHERE export_date = ? AND export_time = ?", (gen_data[0], gen_data[1]))

    if record_exists.fetchone() is None:

        c.execute("INSERT INTO gen_data (export_date, export_time, from_date, to_date)"
                  "VALUES (?, ?, ?, ?)", gen_data)

        id = c.execute("SELECT export_id FROM gen_data WHERE export_id = (SELECT MAX(export_id) FROM gen_data)")
        month_id = id.fetchone()

        for line in badge_data:
            line.append(month_id[0])
            print(line)
            c.execute("INSERT INTO badge_data (badge_id, name, date, first_entry, first_exit, second_entry, second_exit, month_id)"
                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", line[4:])
    else:
        print("A record for given export date already exists.")

    db.commit()
    c.close()
    db.close()
 
Vissiin foreign key on suunnilleen se mitä tässä haen takaa. Eli month_id:stä pitää tehdä foreign key, joka viittaa export_id:hen.

Kannattaako muuten kellonajat syöttää tietokantaan ihan vaan tekstinä vai kannattaisiko muuntaa ne datetime-objekteiksi? Aikavyöhykejutuista ei tässä tarkoituksessa ole mitään hyötyä.
 
Vissiin foreign key on suunnilleen se mitä tässä haen takaa. Eli month_id:stä pitää tehdä foreign key, joka viittaa export_id:hen.
Foreign key on oikea työkalu tuohon.
Kannattaako muuten kellonajat syöttää tietokantaan ihan vaan tekstinä vai kannattaisiko muuntaa ne datetime-objekteiksi? Aikavyöhykejutuista ei tässä tarkoituksessa ole mitään hyötyä.
Kannattaa ehdottomasti tallentaa muuna kuin tekstinä. Jos tietoa pitää hakea tai järjestää ajan mukaan niin se on huomattavasti helpompaa kun se on tallennettu sopivassa formaatissa.
 
Funktio luo kaksi taulukkoa (gen_data ja badge_data). Gen_datassa on kuukausikohtaiset tiedot ja badge_datassa päiväkohtaiset tiedot. Haluaisin sitoa month_id-kentän export_id-kenttään siten, että badge_data-taulukkoon ei saisi lisättyä sellaista riviä, jonka month_id ei vastaa jotain gen_data-taulussa olevaa export_id:tä. Onko tällaisen ominaisuuden lisääminen vaikeaa?

Tosiaan foreign key -liitos:

Koodi:
CREATE TABLE IF NOT EXISTS badge_data
(
  id INTEGER PRIMARY KEY,
  day_id INTEGER,
  badge_id TEXT,
  name TEXT,
  date TEXT,
  first_entry TEXT,
  first_exit TEXT,
  second_entry TEXT,
  second_exit TEXT,
  month_id,
  FOREIGN KEY(month_id) REFERENCES gen_data(export_id)
);

ja tosiaan kaikki ajat kannattaa kääntää unix timestampeiksi ja tallentaa integerinä, koska SQLite ei tue DATETIME datatyyppiä. Konvertiossa kannattaa sitten katsoa, että jos sinun string-muotoiset aikaleimat ovat Suomen ajassa niin ne pitää ensiksi muuttaa UTC-aikaan ja vasta sitten unix timestampiksi, muuten käy siten että Suomen aikaa käsitellään UTC-aikana.

Lisäksi ihmettelen miksi sinulla on day_id laitettu primary keyksi, eikö tauluun ole tarkoitus lisätä usean henkilön saman päivän tietoja? Yllä oma tulkinta taulusta. Myös kiinnittäisin paljon homiota koodin jäsentelyyn ja missä on mitäkin dataa. Esim. SQL-lauseet ei mielestäni koskaan kuulu samaan funktioon missä on datan käsittelyn logiikka.

Tässä oma jäsentely:

Koodi:
class SQLQuery:

    create_gen_data_table = """
        CREATE TABLE IF NOT EXISTS gen_data
        (
            export_id INTEGER PRIMARY KEY AUTOINCREMENT,
            export_date TEXT,
            export_time TEXT,
            from_date TEXT,
            to_date TEXT
        );
    """

    create_badge_data_table = """
        CREATE TABLE IF NOT EXISTS badge_data
        (
            id INTEGER PRIMARY KEY,
            day_id INTEGER,
            badge_id TEXT,
            name TEXT,
            date TEXT,
            first_entry TEXT,
            first_exit TEXT,
            second_entry TEXT,
            second_exit TEXT,
            month_id,
            FOREIGN KEY(month_id) REFERENCES gen_data(export_id)
        );
    """

    get_record = """
        SELECT
        export_date,
        export_time
        FROM gen_data
        WHERE
        export_date = ? AND
        export_time = ?;
    """

    get_export_id = """
        SELECT
        export_id
        FROM gen_data
        WHERE export_id = (
            SELECT MAX(export_id) FROM gen_data
        )
    """

    insert_gen_data = """
        INSERT INTO gen_data
        (
            export_date,
            export_time,
            from_date,
            to_date
        ) VALUES (?, ?, ?, ?);
    """

    insert_badge_data = """
        INSERT INTO badge_data (
            day_id,
            badge_id,
            name,
            date,
            first_entry,
            first_exit,
            second_entry,
            second_exit,
            month_id
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    """

Koodi:
import sqlite3
from sql_query import SQLQuery

DB_NAME = 'wh_db.sqlite'


def open_db_con():
    db = sqlite3.connect(DB_NAME)
    c = db.cursor()
    return db, c


def commit_and_close_db_con(db_connection, cursor):
    db_connection.commit()
    cursor.close()
    db_connection.close()


def create_tables():
    db, c = open_db_con()
    # create tables if not exist
    c.execute(SQLQuery.create_gen_data_table)
    c.execute(SQLQuery.create_badge_data_table)
    commit_and_close_db_con(db, c)


def write_gen_badge_data(gen_data, badge_data):
    db, c = open_db_con()

    # get record
    record_exists = c.execute(
        SQLQuery.get_record,
        (gen_data[0], gen_data[1])
    ).fetchone()

    if record_exists:
        print("A record for given export date already exists.")
        return None

    # insert gen data
    month_id = c.execute(SQLQuery.insert_gen_data, gen_data).lastrowid

    # insert badge data
    for line in badge_data:
        line.append(month_id)
        c.execute(SQLQuery.insert_badge_data, line)

    commit_and_close_db_con(db, c)


def get_mockup_data():
    # day_id, badge_id, name, date, first_entry, first_exit, second_entry, second_exit
    badge_data = [
        [
            1, '00112', 'Erkki', '02-06-2018', '08:00', '11:00', '12:00', '16:00'
        ],
        [
            1, '00113', 'Sampo', '02-06-2018', '08:02', '10:50', '11:50', '16:05'
        ]
    ]
    # export_date, export_time, from_date, to_date
    gen_data = (
        '02-06-2018',
        '08:00',
        '01-05-2018',
        '31-05-2018'
    )

    return gen_data, badge_data


def main():
    create_tables()
    gen_data, badge_data = get_mockup_data()
    write_gen_badge_data(gen_data, badge_data)


if __name__ == '__main__':
    main()
 
Tosiaan foreign key -liitos:

Koodi:
CREATE TABLE IF NOT EXISTS badge_data
(
  id INTEGER PRIMARY KEY,
  day_id INTEGER,
  badge_id TEXT,
  name TEXT,
  date TEXT,
  first_entry TEXT,
  first_exit TEXT,
  second_entry TEXT,
  second_exit TEXT,
  month_id,
  FOREIGN KEY(month_id) REFERENCES gen_data(export_id)
);

ja tosiaan kaikki ajat kannattaa kääntää unix timestampeiksi ja tallentaa integerinä, koska SQLite ei tue DATETIME datatyyppiä. Konvertiossa kannattaa sitten katsoa, että jos sinun string-muotoiset aikaleimat ovat Suomen ajassa niin ne pitää ensiksi muuttaa UTC-aikaan ja vasta sitten unix timestampiksi, muuten käy siten että Suomen aikaa käsitellään UTC-aikana.

Lisäksi ihmettelen miksi sinulla on day_id laitettu primary keyksi, eikö tauluun ole tarkoitus lisätä usean henkilön saman päivän tietoja? Yllä oma tulkinta taulusta. Myös kiinnittäisin paljon homiota koodin jäsentelyyn ja missä on mitäkin dataa. Esim. SQL-lauseet ei mielestäni koskaan kuulu samaan funktioon missä on datan käsittelyn logiikka.

Tässä oma jäsentely:

Koodi:
class SQLQuery:

    create_gen_data_table = """
        CREATE TABLE IF NOT EXISTS gen_data
        (
            export_id INTEGER PRIMARY KEY AUTOINCREMENT,
            export_date TEXT,
            export_time TEXT,
            from_date TEXT,
            to_date TEXT
        );
    """

    create_badge_data_table = """
        CREATE TABLE IF NOT EXISTS badge_data
        (
            id INTEGER PRIMARY KEY,
            day_id INTEGER,
            badge_id TEXT,
            name TEXT,
            date TEXT,
            first_entry TEXT,
            first_exit TEXT,
            second_entry TEXT,
            second_exit TEXT,
            month_id,
            FOREIGN KEY(month_id) REFERENCES gen_data(export_id)
        );
    """

    get_record = """
        SELECT
        export_date,
        export_time
        FROM gen_data
        WHERE
        export_date = ? AND
        export_time = ?;
    """

    get_export_id = """
        SELECT
        export_id
        FROM gen_data
        WHERE export_id = (
            SELECT MAX(export_id) FROM gen_data
        )
    """

    insert_gen_data = """
        INSERT INTO gen_data
        (
            export_date,
            export_time,
            from_date,
            to_date
        ) VALUES (?, ?, ?, ?);
    """

    insert_badge_data = """
        INSERT INTO badge_data (
            day_id,
            badge_id,
            name,
            date,
            first_entry,
            first_exit,
            second_entry,
            second_exit,
            month_id
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    """

Koodi:
import sqlite3
from sql_query import SQLQuery

DB_NAME = 'wh_db.sqlite'


def open_db_con():
    db = sqlite3.connect(DB_NAME)
    c = db.cursor()
    return db, c


def commit_and_close_db_con(db_connection, cursor):
    db_connection.commit()
    cursor.close()
    db_connection.close()


def create_tables():
    db, c = open_db_con()
    # create tables if not exist
    c.execute(SQLQuery.create_gen_data_table)
    c.execute(SQLQuery.create_badge_data_table)
    commit_and_close_db_con(db, c)


def write_gen_badge_data(gen_data, badge_data):
    db, c = open_db_con()

    # get record
    record_exists = c.execute(
        SQLQuery.get_record,
        (gen_data[0], gen_data[1])
    ).fetchone()

    if record_exists:
        print("A record for given export date already exists.")
        return None

    # insert gen data
    month_id = c.execute(SQLQuery.insert_gen_data, gen_data).lastrowid

    # insert badge data
    for line in badge_data:
        line.append(month_id)
        c.execute(SQLQuery.insert_badge_data, line)

    commit_and_close_db_con(db, c)


def get_mockup_data():
    # day_id, badge_id, name, date, first_entry, first_exit, second_entry, second_exit
    badge_data = [
        [
            1, '00112', 'Erkki', '02-06-2018', '08:00', '11:00', '12:00', '16:00'
        ],
        [
            1, '00113', 'Sampo', '02-06-2018', '08:02', '10:50', '11:50', '16:05'
        ]
    ]
    # export_date, export_time, from_date, to_date
    gen_data = (
        '02-06-2018',
        '08:00',
        '01-05-2018',
        '31-05-2018'
    )

    return gen_data, badge_data


def main():
    create_tables()
    gen_data, badge_data = get_mockup_data()
    write_gen_badge_data(gen_data, badge_data)


if __name__ == '__main__':
    main()
Kiitos hyvistä neuvoista. Siirsin SQL-lauseet toiseen paikkaan ja tuosta minun db_writer-funktiosta tulikin heti paljon helpommin tulkittava. Tuo day_id oli vähän hämäävä. Tarkoitin sillä siis ihan vaan juoksevaa rivi-id:tä. Badge_gen-taulun 'date' kolumni taas oikeasti viittaa päivään. Lopullisessa taulukossa rakenne on siis:
Koodi:
create_badge_data_table = """
    CREATE TABLE IF NOT EXISTS badge_data
    (
        id INTEGER PRIMARY KEY,
        badge_id TEXT,
        name TEXT,
        day TEXT,
        first_entry TEXT,
        first_exit TEXT,
        second_entry TEXT,
        second_exit TEXT,
        month_id,
        FOREIGN KEY(month_id) REFERENCES gen_data(export_id)
    );
"""

Miten tuon foreign key -liitoksen luuluu toimia? Vaikka olen lisännyt sen badge_datan month_id-kenttään, niin pystyn silti lisäämään badge_dataan rivejä, joissa on joku ihan hatusta vedetty month_id.

Olen lisännyt noita testirivejä esimerkiksi näin:
Koodi:
c.execute("INSERT INTO badge_data (month_id) VALUES (467)")
Eikö tuosta kuuluisi joku errori tulla?
 
Miten tuon foreign key -liitoksen luuluu toimia? Vaikka olen lisännyt sen badge_datan month_id-kenttään, niin pystyn silti lisäämään badge_dataan rivejä, joissa on joku ihan hatusta vedetty month_id.

Olen lisännyt noita testirivejä esimerkiksi näin:
Koodi:
c.execute("INSERT INTO badge_data (month_id) VALUES (467)")
Eikö tuosta kuuluisi joku errori tulla?
SQLitessä taitaa olla foreign key -tarkistukset disabloituna oletuksena taaksepäin yhteensopivuuden takia.
 
SQLitessä taitaa olla foreign key -tarkistukset disabloituna oletuksena taaksepäin yhteensopivuuden takia.
No tämähän se oli. Olin jo kertaalleen foreign_keysin aktivoinut, mutta kun poistelin ja loin tuota tietokantaa moneen kertaan, niin asetus oli mennyt pois päältä. Ilmeisesti aina tietokannan luomisen jälkeen pitää käydä tuo asetus laittamassa päälle.

Nyt siis sain tuon toimimaan ja tulee tämä errori: FOREIGN KEY constraint failed: INSERT INTO badge_data(month_id) VALUES(345), jos koitan lisätä epäkelpoa id:tä.
 
Kannattaa laittaa se suoraan aina tuohon connect metodin jälkeen:

Koodi:
db = sqlite3.connect(DB_NAME)
c = db.cursor()
c.execute('PRAGMA foreign_keys = 1')

Varmaan kannattaa miettiä ihan PostgreSQL käyttöä niin säästyy monelta ihmetykseltä. Lisäksi suosittelen esim. SQLAlchemyä niin ei tarvitse itse murehtia noista SQL-lauseista ja connection pooleista yksinkertaisissa tapauksissa.

Sit sellainenkin tuli mieleen, että voit määritellä unique constraintin tuolle gen_data taululle niin sinun ei itse tarvitse noita checkailla turhaan koodissa:

Koodi:
        CREATE TABLE IF NOT EXISTS gen_data
        (
            export_id INTEGER PRIMARY KEY AUTOINCREMENT,
            export_date TEXT,
            export_time TEXT,
            from_date TEXT,
            to_date TEXT,
            CONSTRAINT uniq_export_datetime UNIQUE (export_date, export_time)
        );

Jolloin tämä on turhaa:

Koodi:
    record_exists = c.execute(
        SQLQuery.get_record,
        (gen_data[0], gen_data[1])
    ).fetchone()

    if record_exists:
        print("A record for given export date already exists.")
        return None
 
Viimeksi muokattu:
Ja tähän väliin Java-aiheinen kysymys. eli UbuntuLinuxiin työn alla pieni konsolissa pyörivä ohjelma. Tarkoituksena saada käyttäjälle notifikaatio kun jotain tapahtuu, eli yksinkertaisin voisi olla jonkinlainen piip-ääni. Ja vielä silleen ettei tarvitsisi mitään filua ladata. Vaan miten hitossa tuon saa tehtyä.
-java.awt.Toolkit.getDefaultToolkit().beep(); ei toimi
-System.out.print("\007"); ei toimi

Muuta ideaa? Ja ei, tästä ei tehdä Applettia.
 
Kannattaa laittaa se suoraan aina tuohon connect metodin jälkeen:

Koodi:
db = sqlite3.connect(DB_NAME)
c = db.cursor()
c.execute('PRAGMA foreign_keys = 1')

Varmaan kannattaa miettiä ihan PostgreSQL käyttöä niin säästyy monelta ihmetykseltä. Lisäksi suosittelen esim. SQLAlchemyä niin ei tarvitse itse murehtia noista SQL-lauseista ja connection pooleista yksinkertaisissa tapauksissa.

Sit sellainenkin tuli mieleen, että voit määritellä unique constraintin tuolle gen_data taululle niin sinun ei itse tarvitse noita checkailla turhaan koodissa:

Koodi:
        CREATE TABLE IF NOT EXISTS gen_data
        (
            export_id INTEGER PRIMARY KEY AUTOINCREMENT,
            export_date TEXT,
            export_time TEXT,
            from_date TEXT,
            to_date TEXT,
            CONSTRAINT uniq_export_datetime UNIQUE (export_date, export_time)
        );

Jolloin tämä on turhaa:

Koodi:
    record_exists = c.execute(
        SQLQuery.get_record,
        (gen_data[0], gen_data[1])
    ).fetchone()

    if record_exists:
        print("A record for given export date already exists.")
        return None
Koitin lisätä tuota unique constraintia, mutta erroria pukkaa taulua luodessa. Olen katsonut syntaksia moneen kertaan, mutta ei tunnu aukeavan.

Virheilmoitus:
Koodi:
File "C:/Users/Utente-006/Documents/Programming/WhHandler/main.py", line 210, in _db_writer
    c.execute(SQLQuery.create_gen_data_table)
sqlite3.OperationalError: near "(": syntax error

Ja sql-lause näyttää tältä:

Koodi:
CREATE TABLE IF NOT EXISTS gen_data
(
    export_id INTEGER PRIMARY KEY AUTOINCREMENT,
    export_date TEXT,
    export_time TEXT,
    from_date TEXT,
    to_date TEXT
    CONSTRAINT uniq_export_datetime UNIQUE (export_date, export_time)
);

Katselin muualtakin ohjeita, mutta tuollein sen pitäisi olla kai oikein :confused:
 
Koitin lisätä tuota unique constraintia, mutta erroria pukkaa taulua luodessa. Olen katsonut syntaksia moneen kertaan, mutta ei tunnu aukeavan.

Virheilmoitus:
Koodi:
File "C:/Users/Utente-006/Documents/Programming/WhHandler/main.py", line 210, in _db_writer
    c.execute(SQLQuery.create_gen_data_table)
sqlite3.OperationalError: near "(": syntax error

Ja sql-lause näyttää tältä:

Koodi:
CREATE TABLE IF NOT EXISTS gen_data
(
    export_id INTEGER PRIMARY KEY AUTOINCREMENT,
    export_date TEXT,
    export_time TEXT,
    from_date TEXT,
    to_date TEXT
    CONSTRAINT uniq_export_datetime UNIQUE (export_date, export_time)
);

Katselin muualtakin ohjeita, mutta tuollein sen pitäisi olla kai oikein :confused:

to_date TEXT-rivin lopusta puuttuu pilkku?
 
Ja tähän väliin Java-aiheinen kysymys. eli UbuntuLinuxiin työn alla pieni konsolissa pyörivä ohjelma. Tarkoituksena saada käyttäjälle notifikaatio kun jotain tapahtuu, eli yksinkertaisin voisi olla jonkinlainen piip-ääni. Ja vielä silleen ettei tarvitsisi mitään filua ladata. Vaan miten hitossa tuon saa tehtyä.
-java.awt.Toolkit.getDefaultToolkit().beep(); ei toimi
-System.out.print("\007"); ei toimi

Muuta ideaa? Ja ei, tästä ei tehdä Applettia.
Asiasta mitään tietämättä tämä näyttää hyödylliseltä. Tuo taitaa pikemminkin johtaa työpöytäilmoitukseen kuin ääneen, mutta sekin saattaisi kelvata.
 
Asiasta mitään tietämättä tämä näyttää hyödylliseltä. Tuo taitaa pikemminkin johtaa työpöytäilmoitukseen kuin ääneen, mutta sekin saattaisi kelvata.
Jep, thanks.

Muokkasin tuota gen_data-taulua nyt niin, että siinä ei ole enää tekstimuotoisia export_date- ja export_time-kenttiä, vaan yksi kenttä unix timestampille. Lisäksi from_date- ja to_date-kentät on nyt timestamp-muodossa.



Lisäksi myös badge_data-taulun päivämääräkenttä on nyt timestamp. En tiedä onko tästä viimeisestä muunnoksesta mitään hyötyä, mutta tulipahan tehtyä. Nuo itse leimaukset jätän tekstimuotoon.

upload_2018-6-4_12-1-1.png upload_2018-6-4_12-27-59.png

(Sähläsin noitten liitteiden kanssa enkä saa niitä enää pois.)
 
Voisi tälle kai uuden topicin perustaa myös:

Onko suosituksia hyvistä verkkokursseista 2D-peliohjelmoinnin perusteista tai peliohjelmointiympäristöistä? Tutoriaaleja löytyy paljonkin, mutta minulla loppuu motivaatio seurata Unityn videomuotoisia tutoriaaleja, joissa toistetaan perässä kaikki toimet ja pahimmillaan video on kuvattu jollain luennolla. Jos video laahaa tai käy läpi jotain ihan ohjelmoinnin perusjuttuja, on vaikea skipata sitä ylimääräistä osuutta, kun jotain oleellista jää sitten tekemättä.

Lähinnä kiinnostaa tosiaan 2D, ehkä pysyen monissa asioissa simppelimpänä, joten olisi varmaan hyvä jos kurssilla ei käytettäisi Unreal Engineä. Saa myös sisältää teoreettisempaa tavaraa konsepteista tai käytettyjen työkalujen tarjoamista seteistä, tai mennä sivupoluille äänien/efektien/spritejen/muiden assettien tekemiseen.
 
Voisi tälle kai uuden topicin perustaa myös:

Onko suosituksia hyvistä verkkokursseista 2D-peliohjelmoinnin perusteista tai peliohjelmointiympäristöistä? Tutoriaaleja löytyy paljonkin, mutta minulla loppuu motivaatio seurata Unityn videomuotoisia tutoriaaleja, joissa toistetaan perässä kaikki toimet ja pahimmillaan video on kuvattu jollain luennolla. Jos video laahaa tai käy läpi jotain ihan ohjelmoinnin perusjuttuja, on vaikea skipata sitä ylimääräistä osuutta, kun jotain oleellista jää sitten tekemättä.

Lähinnä kiinnostaa tosiaan 2D, ehkä pysyen monissa asioissa simppelimpänä, joten olisi varmaan hyvä jos kurssilla ei käytettäisi Unreal Engineä. Saa myös sisältää teoreettisempaa tavaraa konsepteista tai käytettyjen työkalujen tarjoamista seteistä, tai mennä sivupoluille äänien/efektien/spritejen/muiden assettien tekemiseen.

Suosittelen katsomaan Handmade Heroa (youtube). Siinä koodataan 2D-peli alusta asti C:llä ja jokainen vaihe selitetään. Itsellä nyt 30. jakso menossa :)
Vaatii kyllä vähän kärsivällisyyttä ja oikeaa kiinnostusta jotta jaksaa jokaisen jakson (varsinkin alun platform-koodauksen) katsoa läpi, mutta suosittelen katsomaan jokaisen jakson järjestyksessä koska muuten ei välttämättä ymmärrä kaikkea ja voi helposti turhautua.
 
Suosittelen katsomaan Handmade Heroa (youtube). Siinä koodataan 2D-peli alusta asti C:llä ja jokainen vaihe selitetään.

Oliko tämä vitsi? Kuulostaa kaikin puolin juuri siltä, mitä en hae. Tässä on monta vikaa:

- C-ohjelmointi
- Tuntien pituiset videot, joita on joku 500...
- Kaiken tekeminen alusta asti

Joskus nimenomaan yritin kiinnostua matalan tason ohjelmoinnista Gameboy Advancen kanssa, mutta suurin osa näkemästäni C-koodista on niin luotaan työntävää, ettei se oikein maistunut.

Lähempänä hakemaani taitaa olla esimerkiksi GameMaker Studio 2, Löve tai joku Javascript/HTML5 Canvas -pohjainen engine, tai Unityn 2d-ominaisuudet.

Ongelma vaan on se, etten löydä oikein mielekästä materiaalia, tai laatuvaatimukseni ovat liian korkealla. Haluaisin nimittäin mieluusti jotain "lue tekstiä, pari tehtävää, lue tekstiä, pari tehtävää" -tyylistä materiaalia, jossa joko rakennettaisiin yksi peli tehtävien muodossa ja samalla käytäisiin myös 2D-ohjelmoinnissa vaadittavaa matematiikkaa, tai tehtävät voisivat olla vaikka jonkun yksittäisten toiminnallisuuksien/juttujen lisäämistä jo puolivalmiisiin runkoihin. Tämä olisi ainakin minulle mielekäs tapa opiskella ja ehkä samalla saada ajatuksia miten voisin taitoja hyödyntää, kuin noudattamalla vaan orjallisesti video-ohjeita tai yrittää videoiden pohjalta siirtyä tekemään jotain enemmän tai vähemmän eri ideaa.

[edit] Löven suositus tosiaan tuli toisaalta, sen tutoriaalit ainakin näyttäisivät olevan jo lähempänä sitä mitä haen. Ehkä voisin niitä ainakin kokeilla seuraavaksi.
 
Viimeksi muokattu:
Oliko tämä vitsi? Kuulostaa kaikin puolin juuri siltä, mitä en hae. Tässä on monta vikaa:
...
Ei se vitsi ollut, vaan ajattelin että jos pelialalle haluaa niin on ihan hyvä ymmärtää vähän laajemmin miten pelimoottorit ja sen komponentit toimivat. Tietysti pitää miettiä mitä roolia haluat pelikehityksessä, eli onko engineen liittyvää koodausta vai ihan pelilogiikan koodausta. Uskoisin että sinulle jälkimmäinen on se oikeampi vaihtoehto.

jossa joko rakennettaisiin yksi peli tehtävien muodossa ja samalla käytäisiin myös 2D-ohjelmoinnissa vaadittavaa matematiikkaa
...
Handmade Herossa juurikin käydään 2D-matematiikkaa laajasti läpi.

Ehkä youtube on sinulle väärä paikka etsiä. Kaupallisiakin tutoriaaleja löytyy ja niiden luulisi olevan laadukkaampia. Esimerkiksi täältä: Online Courses - Anytime, Anywhere | Udemy (nuo "tarjoukset" ovat sitten ilmeisesti aina voimassa, viimeksi katsoin viikko sitten ja silloinkin oli "5h jäljellä").
 
Niin no - ehkä olisi pitänyt lähtökohdat määrittää tarkemmin: Pelialalle ei ole ainakaan tällä hetkellä niin mitään aikomusta, ihan vain harrastepohjaista tutustumista ja alkeita. :) Kun koodaa 9-17 työssä fullstackia, ei ihan riitä innostus vielä alkaa kovin intensiivisesti opiskelemaan.

Youtubesta en tosiaan arvellutkaan löytävän mitään minulle suoraan sopivaa, enkä sieltä ole oikeastaan haeskellutkaan. Udemy, Course ja Edx ovat vähintään niminä tuttuja, mutta niiden laatu voi olla ihan mitä tahansa. Kokemuksia on mm. Ruby on Rails kurssista, jossa ensin pari viikkoa huonosti videoituja luentoja ja jotain kompamonivalintakysymyksiä, sitten yhtäkkiä isokokoinen Rails-koodi eteen ja "täällä on myös yksi bugi". Onneksi tässä tapauksessa maksajana en ollut minä, ja kurssin pystyi helposti jättämään keskenkin. Linkittämäsi Udemyn kurssit ovat tähtimääriltään kovia, mutta kun katsoo sisältöä, niin "50h on-demand videos", "Certificate of completion" ja sisällysluettelossa joku 9 kysymyksen quiz joka osion lopussa... kuulostaa kumman tutulta.

Sokkona en tuollaisesta materiaalista ala maksamaan yhtikäs mitään. Nuo "tää on 190$ kurssi mutta vain sulle 10$" on suurin piirtein yhtä luotettavan kuuloinen kuin TV shop.

Tämän takia toivoinkin, että ehkä joku muu on jo löytänyt jotain hyviä kursseja, kirjoja tai tekstipohjaisia tutoriaaleja, johon osaa ohjata - maksullisia tai ei. Hyvästä kurssista voisi lompakko avautuakin. Mutta ehkä odotukseni ovat vain utopistiset, kun toivomuksissa olisi löytää Ohjelmoinnin MOOC tai Full stack Open 2018 tapaista ja tasoista materiaalia.
 
Miten olio-ohjelmointia kannattaisi lähteä harjoittelemaan? Mulla on perusteet joten kuten hallussa, koska tuolla Udemyn Python-kurssilla tästäkin aiheesta oli oma osionsa, mutta en siltikään oikein osaa sitä soveltaa. Nyt kun olen pari omaa skriptiä tehnyt, niin lähden aina ratkaisemaan ongelmaa proseduraalisesti enkä edes harkita luokkien käyttöä.

Nyt siis aloitan suunnittelun jakamalla skriptin osiin ja teen noista osista erilliset funktiot. Nämä funktiokutsut laitan sitten vaan peräkkäin main()-funktioon. Toimii ihan hyvin näissä pikkuohjelmissa, mutta tämä ei varmaan ole paras lähestymistapa, jos joskus pääsee sellaiselle tasolle, että pystyy tekemään jotain isompaa.
 
Kumma miten mulle ysärin alussa oliojutut kolahti ihan kybällä, kun tutustuin Dataflex 3 -kehittimeen ja C++:aan. Olin sitä ennen tehnyt juttuja Pascalilla ja C:llä ja silloinkin tein asioista "oloita" tyyppeinä tai struckteina ja niille sopivat funkkarit.

Mutta sitten tuli C++ ja Object Pascal ja lopulta Java ja vähän Pythoniakin, ja aina on on olioilla menty. Se vain tuntuu niin luontaiselta. Olio on asia, ja siihen liittyvät metodit eli funkkarit.

Sitä vierastan, kun ihmiset puhuu scripteistä. Oikeat ongelmointikielet ei liity mitenkään skripteihin ;)
 
Oliot on itsenäisiä asioita ja niihin liittyviä toimintoja. Ensimmäiset oliokielet kuten Ada oli "object based", mutta kun mukaan tuli lisää juttuja, niin syntyi "object oriented". Tähän liittyy kehittyneempiä juttuja kuten periyvyys ja monimuotuisuus.

Tietty nykyään on mukana jopa Javassa ja C++:ssa funktionaalisia juttuja, ja ne vaan täydentää asiaa.
 
Miten olio-ohjelmointia kannattaisi lähteä harjoittelemaan? Mulla on perusteet joten kuten hallussa, koska tuolla Udemyn Python-kurssilla tästäkin aiheesta oli oma osionsa, mutta en siltikään oikein osaa sitä soveltaa. Nyt kun olen pari omaa skriptiä tehnyt, niin lähden aina ratkaisemaan ongelmaa proseduraalisesti enkä edes harkita luokkien käyttöä.

Nyt siis aloitan suunnittelun jakamalla skriptin osiin ja teen noista osista erilliset funktiot. Nämä funktiokutsut laitan sitten vaan peräkkäin main()-funktioon. Toimii ihan hyvin näissä pikkuohjelmissa, mutta tämä ei varmaan ole paras lähestymistapa, jos joskus pääsee sellaiselle tasolle, että pystyy tekemään jotain isompaa.
En osaa antaa kovin hyviä lähtökohtia, mutta yksi tapa on varmastikin ohjelmoidessa miettiä aina, minkä kaiken voi ajatella olioksi ja sitten kyseisistä asioista olioita. Kun olioita tarpeeksi käyttää, asiat alkavat hahmottua paremmin, mutta aluksi asiaa voi joutua miettimään enemmän ihan tietoisestikin, koska harva varmaan ajattelee asioita luontaisesti olioina, vaikka jälkikäteen katsottuna monet asiat voikin sellaisiksi ajatella.
 
Tietokannan taulu on hyvä esimerkki luokasta ja yksi rivin taulusta on yksi luokan olio (instanssi). Luokka voi sitten periä metodeja isäntäluokalta jolla käsitellään tietokannan yhteyksiä ja tallennusmekanismeja.
Yleisesti jos sinulla on jokin datamalli jonka tietojen käsittelyyn tarvitaan dedikoituja funktioita niin silloin kannattaa harkita luokkien käyttöä. Funktiot voidaan sitten laittaa luokkaan metodeiksi, jolloin datan malli ja käsittely on yhdessä paikassa.
 
  • Tykkää
Reactions: ted
Tiedostojen synkronisointia haluaisin koittaa toteuttaa itse laitteiden välillä. Muuten se hoituisi sshfs:llä, paitsi Androidille se vaatii roottauksen. Puhelimeni on muutenkin jo aivan ikäloppu, Syncthing:kään ei siinä toiminut. SSH on jo valmiina, niin sen päälle olisi luonnollisinta rakentaa yksinkertainen systeemi.

Puhelimelle sen voisi toteuttaa vaikkapa niin, että valitaan hakemisto, joissa olevien tiedostojen kohdalla synkronointi toteutaan SSH-palvelimen kanssa. Lisätyt tiedostot lähetetään heti palvelimelle ja palvelimen tiedostot voidaan synkronoida napin painallauksella, niin ei tarvitse toteuttaa server push:a. Itse tiedostojen siirron voisi toteuttaa portatuilla binääreillä, joita on jo kaiketi valmiina, vaikka rsync:llä, tai sitten vastaavilla Java-kirjastoilla. SSH-agentti olisi ehkä hyvä olla myös, jos haluaa käyttää salasanalla suojattua avainta kirjautumiseen, koska yhteys voi luonnollisesti katketa usein.

Sshfs:n puuttumista omalle puhelimelleni, koska en ole sitä rootannut, olen jo harmitellut pidempään, tällainen ratkaisu tuli juuri nyt mieleen. En ehtinyt vielä ajattelemaan sen kummemmin, miltä kuulostaa? Vai löytyisikö tällainen jo? Olen etsinyt sshfs-toteuksia ja yhden löysin, mutta fuse:n takia se tosiaan vaatii roottauksen, eikä taida edes toimia kaikilla malleilla (https://play.google.com/store/apps/details?id=ru.nsu.bobrofon.easysshfs).

Androidille en ole tehnyt vielä yhtään ohjelmaa, vähän vain tutkinut dokumentaatiota. Mutta kälin ei kaiketi tarvitsisi olla kovinkaan monimutkainen.

Edit: Olisi hyvä olla taustaprosessi kuuntelemassa hakemistoon lisättäviä tiedostoja, niin tiedostot siirrettäisiin palvelimelle, käytti sitten mitä hyvänsä tapaa kopioida tiedostot hakemistoon. Ehkä tähän on Androidin API:ssa jo toteutus tai sitten muistaakseni C:n select:llä pystyi toteuttamaan tämän ja epoll taisi olla uudempi ja parempi vielä.
 
Viimeksi muokattu:
Minkä takia en pysty tappamaan prosessia tällä scriptillä?
Käyttiksenä Linux raspberrypi 4.14.34-v7+
Koodi:
kill -15 `pidof regni-server` #toimii komentoriviltä

Koodi:
#!/bin/bash
nodepid=$(pidof regni-server)
echo "Stopping PID : "$nodepid
kill -15 $nodepid               #ei toimi
echo "Done"

Tulostaa:
Koodi:
Restart server
Stopping PID : 1324
: arguments must be process or job IDs
Done
 

Uusimmat viestit

Statistiikka

Viestiketjuista
261 839
Viestejä
4 548 799
Jäsenet
74 851
Uusin jäsen
hieunguyen

Hinta.fi

Back
Ylös Bottom