Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  15 1459
Hei.
Jeg sitter med et skoleprosjekt i java og har satt meg litt fast.
Gruppa mi lager et program som skal være et lege/pasient resept-register.

Jeg sitter fast på en spesifikk funksjon vi skal lage og trenger litt hjelp.
Man skal kunne søke opp en lege/pasient etter navn, og alle treff på dette navnet skal komme opp i en liste.
Man skal så kunne klikke på en av personene i denne lista, også skal man kunne få opp detaljert info om den personen i et annet vindu.

Det jeg ikke vet hvordan vi skal få til er det at info om en person kommer opp når man klikker på noen i lista.
Jeg vet hvordan jeg skal få søkeresultatet mitt til å legge seg i lista, men siden flere personer kan hete det samme må jeg ha med den personens ID også for å kunne slå opp vedkommende og hente ut hans info.
Alle personer er lagret som objekter i en dynamisk datastruktur. Kan jeg da legge person-objektet rett i lista og bare kalle opp den personens toString()-metode? Eller fungerer ikke dette?

Grunne til at jeg spør og ikke tester er pga jeg ikke får testa noe før jeg kommer på skolen igjen i morgen, men jeg skulle gjerne visst litt mer om dette på forhånd så vi slipper å bruke så mye tid på eksperimentering i morgen.


PS: JList er vel den beste(eneste?) måten å skrive ut de klikkbare søkeresultatene i?
PPS: Hvis noen har noen bedre forslag på hvordan dette kan gjøres, fyr løs! Alle forslag mottas med takk
One of the good guys
2rs1's Avatar
JList har en konstruktør som tar Object[] som input, du styrer hva som vises i lista med objektets toString()-metode. Dump søkeresultatene ned i f.eks. et personarray (person[]), bruk dette som input til JList og bruk getSelectedValue() eller lignende for å hente ut objektet du skal vise frem.
:(){ :|:& };:
tripflag's Avatar
Om du har en liste over IDer som samsvarer med oppføringene i lista (et array med samme lengde, personen på linje 7 i lista er IDen på samme posisjon i arrayet) kan du bare hente ut indexen som ble klikka på.

Prøvde nettopp å leke litt med JList, fant ut at den har en egen event for MouseClicked. Der kan du kalle opp metoden getSelectedIndex(); for å få indexen i arrayet som IDen ligger i.
Det du eventuelt kan gjøre, dersom toString() blir for primitivt, er å implementere ListCellRenderer. Det gir deg en del flere muligheter når det gjelder å vise fram dataene.
Hobbit
harald25's Avatar
Trådstarter
Awesome!
Da har jeg noe å jobbe utifra i morgen.

Takk takk!
Sitat av tripflag Vis innlegg
Om du har en liste over IDer som samsvarer med oppføringene i lista (et array med samme lengde, personen på linje 7 i lista er IDen på samme posisjon i arrayet) kan du bare hente ut indexen som ble klikka på.

Prøvde nettopp å leke litt med JList, fant ut at den har en egen event for MouseClicked. Der kan du kalle opp metoden getSelectedIndex(); for å få indexen i arrayet som IDen ligger i.
Vis hele sitatet...
Å hente ut ting fra en JList ved hjelp av indeks er en veldig dårlig måte å gjøre det på. Jeg anbefaler faktisk å implementere en modell til JList, ved å subklasse AbstractListModel. Eclipse er behjelpelig med å legge inn de nødvendige metodene. Modellen kan f.eks. ta i mot en List<Person>. Fordelen med modell-metoden er at modellen tar seg av å oppdatere visningen hvis lista blir endret. Det gir også mye mer kontroll på hvordan ting skal vises, siden man ikke er låst til at den skal vise tekst fra toString()-metoden.

harald25: Programutviklingsfaget på HiO? :>

http://www.iu.hio.no/~kjetilg/uvstof....html#modeller
Den er riktignok for en JTable, men tankegangen med å lage en egen modell blir likt for JList.

Her er kode som kan brukes for klikkbart resultat:

Kode

dinJList.addMouseListener( new MouseAdapter()
		{
			public void mouseClicked( MouseEvent e )
			{
				if ( e.getClickCount() == 1 )
				{
					gjørNoe();
				}
			}
		} );
Rettelse (siden det ikke går an å trykke edit lenger): Å hente ut data fra en liste/array ved hjelp av indeksen fra en JList er en dårlig måte å gjøre det på. Det er bedre å ha en modell som gjør at man kan hente objektene direkte i JListen, og som også tillater at man endrer innholdet underveis.
:(){ :|:& };:
tripflag's Avatar
Sitat av Nichotin Vis innlegg
Å hente ut ting fra en JList ved hjelp av indeks er en veldig dårlig måte å gjøre det på.
Vis hele sitatet...
Virkelig? Jeg tenkte på noe slikt:

Kode

    class Persondata {
    public int id;
        public String navn;
        public Persondata(int id, String navn) {
            this.navn = navn;
            this.id = id;
        }
        @Override
        public String toString() {
            return navn;
        }
    }
    private Persondata[] data;

    @Action
    public void preplist() {
        data = new Persondata[] {
            new Persondata(17, "Louise"),
            new Persondata(23, "Tabitha"),
            new Persondata(44, "Montmorency"),
            new Persondata(56, "Tabitha"),
            new Persondata(82, "Osmond")};
        jList1.setListData(data);
    }

    private void jList1MouseClicked(java.awt.event.MouseEvent evt) {
        int i = jList1.getSelectedIndex();
        javax.swing.JOptionPane.showMessageDialog(null,
            "HELLO THE USER ID IS ~" + data[i].id + "~ THANKS AND HAEV A GOOD DAY");
    }
...hvor data er søkeresultatet, og preplist() kalles i slutten av metoden som utførte søket. Droppet get/set metoder siden lol bloat.

Men joda, kan vel se for meg hvordan det går litt imot tankegangen om å gjøre alt så abstrakt som mulig. Har ikke jobbet med så fryktelig store prosjekter enda...
Sist endret av tripflag; 18. mai 2010 kl. 21:49.
Joda, det funker, men det er definitivt ikke best practice når det kommer til programmering! Problemet med å bruke indeks i sånne operasjoner er at det er avhengig av at indeksen korresponderer med listen eller arrayen bak. Det blir mye mer klønete kode med en gang du skal begynne å legge til noe, slette noe eller sortere. Siden dette var snakk om søkeresultater blir det mye ekstraarbeid med å eventuelt matche en liste/array med søkeresultater med en annen liste/array som skal lagre disse objektene.

Ta dette eksempelet på en modell jeg kjapt kokte sammen:

Kode

public class ListeModell<T> extends AbstractListModel
{
	private List<T> liste;
	public ListeModell(List<T> liste)
	{
		this.liste = liste;
	}
	
	public Object getElementAt( int index )
	{
		if(index >= 0 && index < liste.size())
		{
			return liste.get(index);
		}
		return null;
	}

	public int getSize()
	{
		return liste.size();
	}
}
Den kan settes som modell på en JList, og gjør at JListen viser objektene som er i List<T> liste. Når man trykker på JListen kan man bruke funksjonen getElementAt(jlisten.getSelectedIndex()) for å få ut objektet som korresponderer til den indeksen direkte, uten å måtte kalle noe selv på arrayet eller listen den ligger i. Ved å implementere metoden getValueAt(int indeks) har man mer kontroll på hva som eventuelt skal vises for hver linje, hvis man ikke vil bruke objektenes toString().

Forresten: JTable kan også brukes til klikkbare søkeresultater, da har du muligheten til å legge mer informasjon i forskjellige kolonner.
Sist endret av Nichotin; 18. mai 2010 kl. 22:02.
1. Det er i utgangspunktet ikke meningen at man skal fange opp denne type events i en JList med MouseListener. Bruk heller ListSelectionListener.

2. Jeg er ikke enig i at det for din del har noen hensikt å definere din egen listemodell. Jeg tar da et lite forbehold om at du ikke senere skal implementere noe som gjør at de eksisterende swing modellene ikke strekker til. Jeg ville heller gjort som du opprinnelig tenkte og lagt Persondata objektene rett i lista. Så kan du overskrive toString metoden i dem til den teksten du vil objektet skal representeres med i JList'en - det er nettopp slike ting toString er til for!

3. Siden du sa du fikk oppdatert lista greit regner jeg egentlig med du allerede er klar over at default modellen til en JList har veldig begrensede muligheter og at det kan være lurt å skifte den ut med for eksempel DefaultTableModel.

Jeg ville gått for noe slik:

Kode

public class Persondata {
    private int id;
    private String navn;
		
    public Persondata(int id, String navn) {
        this.id = id;
        this.navn = navn;
    }
		
    public int getId() {
        return id;
    }
		
    public String getNavn() {
        return navn;
    }
		
    public String toString() {
        return navn;
    }
}

DefaultListModel model = new DefaultListModel();
for (Persondata pd : new Persondata[] {
             new Persondata(17, "Louise"),
             new Persondata(23, "Tabitha"),
             new Persondata(44, "Montmorency"),
             new Persondata(56, "Tabitha"),
             new Persondata(82, "Osmond")}) {
    model.addElement(pd);
}
JList list = new JList(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addListSelectionListener(new ListSelectionListener() {
    public void valueChanged(ListSelectionEvent e) {
        if (e.getValueIsAdjusting()) {
            JList source = (JList)e.getSource();
            Persondata pd = (Persondata)source.getSelectedValue();
            // <Gjør noe fornuftig med pd>
        }
    }
});
Sist endret av Bjornix; 19. mai 2010 kl. 07:43.
Bornix: Ja, du har rett i det med å bruke ListSelectionListener. Kom nå på hvorfor jeg har brukt MouseAdapter selv, og det er for å kunne fange opp dobbeltklikk også (der strekker ikke ListSelectionListener til, dessverre).

Når du sier det er nok DefaultListModel brukbart i dette tilfellet, det er vel heller på JTable at det er et mer skrikende behov for en egen modell. Synes fremdeles det er greit å ha en modell som tar i mot en List, dog, til den type oppgave som trådstarter løser (programutviklingsprosjekt, om ikke jeg tar helt feil).
Sitat av Nichotin Vis innlegg
Bornix: Ja, du har rett i det med å bruke ListSelectionListener. Kom nå på hvorfor jeg har brukt MouseAdapter selv, og det er for å kunne fange opp dobbeltklikk også (der strekker ikke ListSelectionListener til, dessverre).
Vis hele sitatet...
Ja, ser den. Strengt talt kan man jo i veldig mange tilfeller, muligens også i trådstarter sitt, klare seg med å velge MouseListener fremfor ListSelectionListener. Forskjellen blir nok merkbar først når man ønsker å håndtere eventet et sted der JList'en ikke er i scope og man er avhengig av ListSelectionEvent.getSource() for å finne tilbake til den.

Sitat av Nichotin Vis innlegg
Når du sier det er nok DefaultListModel brukbart i dette tilfellet, det er vel heller på JTable at det er et mer skrikende behov for en egen modell.
Vis hele sitatet...
Både ja og nei egentlig. Som for JList er den standard abstrakte modellen (AbstractTableModel) ganske ubrukelig, mens DefaultTableModel som man kan benytte isteden duger til en del. Når det er sagt da så er man ofte interessert i å skreddersy tabeller i enda større grad enn lister og jeg kan egentlig ikke huske sist gang jeg brukte en tabell uten å lage min egen modell til den så du har vel et poeng

Sitat av Nichotin Vis innlegg
Synes fremdeles det er greit å ha en modell som tar i mot en List, dog, til den type oppgave som trådstarter løser (programutviklingsprosjekt, om ikke jeg tar helt feil).
Vis hele sitatet...
Er jo det med å bruke klassebiblioteket når man kan og "extende" (i mangel på et bedre ord) når man "må". Så lenge DefaultTableModel har den nødvendige funksjonaliteten ville nok jeg latt være og heller brukt toString til det den er ment for - returnere en tekst representativ for objektet. Men det blir egentlig litt smak og behag og jeg tviler på om fastsettelsen av karakteren kommer til å stå og vippe på det akkurat

Jeg lurer forresten på om vi to kan ha gått i samme kull på HiO? Dataingeniør med start i 2005. Noe som sier meg at jeg en gang for lenge siden fant ut av dette, men har glemt nå om det var deg.
Hobbit
harald25's Avatar
Trådstarter
Jeg har testet litt og ting var dessverre ikke så straight forward som jeg hadde håpet.
Har et par småproblemer med andre ord :P

Når man søker på en person og får opp flere med samme navn må man nødvendigvis få opp mer info enn bare navnet for å vite hvem man vil klikke seg videre på. Er det JTable som må til for kunne vise mer enn bare navnet da?

Jeg trodde også at jeg skulle lett kunne få søketreffene min til å legge seg i lista/tabellen, men har et lite problem der og.
Når man skal søke opp en person trykker man på en knapp og et nytt vindu med søkebokser osv kommer opp.
Det er i dette vinduet jeg vil at lista/tabellen skal komme opp, men da må jeg vel lage en tom liste/tabell først som så fyllles inn med søkeresultatet etter at man har trykket søk.
Kan jeg bare opprette lista/tabellen med en tom array (ellernoe) i det vinduet åpnes, også sette alt innholdet fra søket mitt etterpå?
Jeg vil aldri trenge å sette ett og ett felt, men hver gang man søker skal alt innholdet som var der byttes ut med det nye søket. Hva er letteste metode å gjøre dette på.

Og til slutt, kan jeg fylle objekter rett inn i en JTable? Sånn at når jeg henter ut det valget i tabellen brukeren klikker på så kan jeg bare bruke objektet direkte for å kalle opp riktig metode for utskrift?


PS: Til den som spurte. Ja, jeg går på informasjonsteknologi på HiO ja, og faget er programutvikling.
Sist endret av harald25; 19. mai 2010 kl. 12:19.
Sitat av harald25 Vis innlegg
Når man søker på en person og får opp flere med samme navn må man nødvendigvis få opp mer info enn bare navnet for å vite hvem man vil klikke seg videre på. Er det JTable som må til for kunne vise mer enn bare navnet da?
Vis hele sitatet...
En JTable burde egne seg godt til dette ja.

Sitat av harald25 Vis innlegg
Når man skal søke opp en person trykker man på en knapp og et nytt vindu med søkebokser osv kommer opp.
Det er i dette vinduet jeg vil at lista/tabellen skal komme opp, men da må jeg vel lage en tom liste/tabell først som så fyllles inn med søkeresultatet etter at man har trykket søk. Kan jeg bare opprette lista/tabellen med en tom array (ellernoe) i det vinduet åpnes, også sette alt innholdet fra søket mitt etterpå?
Jeg vil aldri trenge å sette ett og ett felt, men hver gang man søker skal alt innholdet som var der byttes ut med det nye søket. Hva er letteste metode å gjøre dette på.
Vis hele sitatet...
Siden lister og tabeller i prinsippet ikke er veldig ulikt bygget opp blir fremgangsmåten omtrent den samme, men for tabeller vil du i enda større grad ha behov for å legge til egen funksjonalitet så jeg støtter meg til Nichotin om å lage din egen modell. Du har valget mellom å utvide en AbstractTableModel eller en DefaultTableModel. Førstnevnte er best hvis du vil starte fra scratch og siste er å foretrekke hvis du kan bruke det som finnes, men bare trenger å legge til litt ekstra. Jeg ville valgt det siste:

Kode

public class MyTableModel extends DefaultTableModel {
    public MyTableModel() {
        populate(new Persondata[0]);
    }
		
    public void populate(Persondata[] pd) {
        // 1. Fjerne rader fra tidligere søk
        // 2. Legge til pd array rad for rad via
        //    den arvede metoden addRow(Object)
        // 3. Hvis det er slik at vi ønsker at
        //    tabellen alltid skal inneholde
        //    minimum x antall rader må vi sjekke
        //    om pd.length < x. Hvis den er det
        //    må vi legge til x - pd.length antall
        //    blanke rader på slutten av tabellen.
    }
}
Sitat av harald25 Vis innlegg
Og til slutt, kan jeg fylle objekter rett inn i en JTable? Sånn at når jeg henter ut det valget i tabellen brukeren klikker på så kan jeg bare bruke objektet direkte for å kalle opp riktig metode for utskrift?
Vis hele sitatet...
Nja. En JTable vet ikke selv hva slags objekter den inneholder. For å legge til rader eller hente ut info fra den kommuniserer du altså med modellen som ligger i bakkant av tabellen, som nevnt over. Modellen over kan brukes slik for å sette inn et array av søketreff:

Kode

JButton searchButton = new JButton("Søk");
searchButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        Persondata[] pd = <array av søketreff>
        MyTableModel model = (MyTableModel)table.getModel();
        model.populate(pd);
    }
});
For å lytte til klikk i tabellen bruker du en ListSelectionListener på tabellens ListSelectionModel:

Kode

ListSelectionModel lsm = table.getSelectionModel();
lsm.addListSelectionListener(new ListSelectionListener() {
    public void valueChanged(ListSelectionEvent e) {
        ...
    }
});
Har selv gjort det på ca. denne måten (har tilpasset eksempelkoden her litt, blant annet ved å bruke standard List istedenfor den subklassede arraylisten vi har brukt (som inneholder kolonnenavn og derfor ikke trenger å få det satt med konstruktør).

Anyways;
Dette er en subklassing av AbstractTableModel for datatyper som extender kolonnetekst. Har gjort det slik at de datatypene jeg vil skal brukes med en JTable extender grensesnittet Kolonnetekst. Da har de en metode getKolonnetekst() som returnerer en List<String> med den teksten som skal vises i de ulike kolonnenne. Metodene som er på engelsk uten JavaDoc har blitt arvet fra AbstractTableModel. hentData-metoden er laget for å hente ut det objektet som ligger på en rad. setData bytter dataen som skal vises.

Synes dette fungerte som en veldig bra løsning til en slik type oppgave som trådstarter illustrerer (tok den med boligmegler selv, fra samme side, siden jeg tar opp akkurat det faget der).

Kode

import java.util.List;

import javax.swing.table.AbstractTableModel;

/**
 * Modell som brukes for å vise en List<T> i en JTable.
 *
 * @param <T> datatypen på listen som skal vises
 */
public class TabellModell<T extends Kolonnetekst> extends AbstractTableModel
{
	private static final long serialVersionUID = 2898866587762091821L;

	private String[] kolonnenavn;
	private List<T> data;

	/**
	 * Konstruerer en TabellModell for List<T> data.
	 * @param data listen modellen skal vise
	 * @param kolonnenavn
	 */
	public TabellModell( List<T> data, String[] kolonnenavn )
	{
		this.data = data;
		this.kolonnenavn = kolonnenavn;
	}

	public int getColumnCount()
	{
		return kolonnenavn.length;
	}

	public int getRowCount()
	{
		return data.size();
	}

	public Object getValueAt( int rad, int kolonne )
	{
		if ( rad >= 0 && rad < data.size() && kolonne >= 0
				&& kolonne < kolonnenavn.length )
		{
			return data.get( rad ).getKolonnetekst().get( kolonne );
		}
		return null;
	}

	/**
	 * Henter objekt fra en gitt rad.
	 * @param rad radnummer
	 * @return hvis radnummeret er innenfor antallet rader, returneres objektet, hvis ikke returneres null
	 */
	public T hentData( int rad )
	{
		if ( rad >= 0 && rad < data.size() )
		{
			return data.get( rad );
		}
		else
		{
			return null;
		}
	}

	public String getColumnName( int kolonne )
	{
		if ( kolonnenavn.length > kolonne )
		{
			return kolonnenavn[kolonne];
		}
		else
		{
			return String.valueOf( kolonne + 1 );
		}
	}

	/**
	 * Setter en ny liste modellen skal vise.
	 * @param data ny liste med data
	 */
	public void setData( List<T> data )
	{
		this.data = data;
	}
}

Bjornix: Startet på dataingeniør i 2007.
Sist endret av Nichotin; 21. mai 2010 kl. 11:11.
Sitat av Nichotin Vis innlegg
Bjornix: Startet på dataingeniør i 2007.
Vis hele sitatet...
Kanskje du har hatt GUI & C++ i vår? Jeg tok opp det. Hvis ikke så er det bare jeg som surrer
Tok GUI-programmering og C++ i år ja :>