19. marts 2003 - 19:03Der er
23 kommentarer og 1 løsning
Swing guru søges problem med tabbedpane
Jeg har et lille (stort) problem med mit porgram...
Jeg har lavet en main klasse med tabbedpane, som samler en masse i klasser til fanebladsprogram...Problemet er bare, at min klasse, som hedder Spm3 ligger sig henover de andre faneblade....Hvorfor gør den det og hvordan ændre man det?? Layoutet skal helst forblive på den måde som klassen Spm3 ser ud, men man skal jo helst kunne vælge de andre faneblade også
Koden er herunder - indsat to klasser (main og Spm3)
import java.sql.*; import javax.swing.*;
public class TaxaBagger { static Connection con; public static void main(String[] args) throws Exception
{
//load driveren og opret en forbindelsesobjekt til taxa2 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:taxa2");
JFrame frame = new JFrame ("Layout Manager Demo"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setTitle("TAXA"); //titel på GUI JTabbedPane tp = new JTabbedPane(); tp.addTab ("Oversigt", new IntroPanel()); //kalder de forskellige klasser tp.addTab ("Spm 3", new Spm3(con, frame)); tp.addTab ("Spm 3b", new Spm3b(con)); tp.addTab ("Spm 4", new Spm4(con)); tp.addTab ("Spm 5", new Spm5(con)); tp.addTab ("Spm 6", new Spm6(con)); tp.addTab ("Spm 7", new Spm7(con)); tp.addTab ("Spm 8", new Spm8(con));
public class Spm3 extends JPanel implements ActionListener { private JFrame frame; private JPanel panelmain, panel1, panel2, panel3, panel4;
private JButton søg, slut; //trykknapper til hhv. at søge i databasen og afslutte private JTextField vognnr, dato; //tekstfelter til hhv. vognnr og dato private JTextArea resultat; //tekst felt til at udskrive resultat private int WIDTH = 210, HEIGHT = 170; private String resultatUd; private DataBase database; private Connection con; //databaseforbindelses-objektet
public Spm3(Connection con, JFrame fr)
//konstruktør, sætter vinduet op { this.con= con; //overfør den modtagne databaseforbindelse
JLabel input1 = new JLabel("Indtast vognummer"); //skriv ledeteksten 'Vognnr' vognnr= new JTextField(10); vognnr.addActionListener(this); //definer og tilføj tekstfeltet vognnr
JLabel input2 = new JLabel("Indtast dato"); dato= new JTextField(10); dato.addActionListener(this);
søg= new JButton("Søg"); //definer og tilføj søg-knappen
søg.addActionListener(this); //registrer søg-knappen, så tryk på //den kan opfanges
slut= new JButton("Afslut"); //definer og tilføj slut-knappen
slut.addActionListener(this); //registrer slut-knappen, så tryk på den kan opfanges
panelmain = new JPanel(); panelmain.setLayout(new BoxLayout (panelmain, BoxLayout.Y_AXIS));
//Panel til søg vognnr og dato panel1 = new JPanel(); panel1. setLayout(new FlowLayout(FlowLayout.LEFT)); panel1.setBorder(new javax.swing.border.TitledBorder("Spørgsmål 3"));
//Panel til textArea panel2 = new JPanel(); panel2. setLayout(new FlowLayout(FlowLayout.LEFT)); panel2.setBorder(new javax.swing.border.TitledBorder("Resultat"));
//Panel til afslut knap panel3 = new JPanel(); panel3. setLayout(new FlowLayout(FlowLayout.LEFT));
public void actionPerformed(ActionEvent e) //metode, der kaldes automatisk, når brugeren trykker på én af de registrerede //trykknapper (søg eller slut). { if (e.getSource() == vognnr || e.getSource() == dato || e.getSource() == søg) { try { resultatUd=database.udskrivspm3a(vognnr.getText(), dato.getText()); resultat.setText(resultatUd); } catch(Exception ex){System.out.println(ex);} } else if (e.getSource()==slut) //ellers hvis det var slut-knappen { try { con.close(); //nedlæg forbindelsen til myDB } catch (Exception ex){System.out.println(ex);} System.exit(0); //afslut } } }
public class TaxaBagger { static Connection con; public static void main(String[] args) throws Exception
{
//load driveren og opret en forbindelsesobjekt til taxa2 // Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// Connection con = DriverManager.getConnection("jdbc:odbc:taxa2");
JFrame frame = new JFrame ("Layout Manager Demo"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setTitle("TAXA"); //titel på GUI JTabbedPane tp = new JTabbedPane(); // tp.addTab ("Oversigt", new IntroPanel()); //kalder de forskellige klasser tp.add ("Spm 3", new Spm3(con, frame)); tp.add("2", new JPanel()); // tp.addTab ("Spm 3b", new Spm3b(con)); // tp.addTab ("Spm 4", new Spm4(con)); // tp.addTab ("Spm 5", new Spm5(con)); // tp.addTab ("Spm 6", new Spm6(con)); // tp.addTab ("Spm 7", new Spm7(con)); // tp.addTab ("Spm 8", new Spm8(con)); /** * Kommenteret ud, da jeg ikek har dem * "2", er bare et dummy panel for at testt */
frame.getContentPane().add(tp, BorderLayout.CENTER); /** * Tilføjet BorderLayout.CENTER her, da dit JFrame bruger BorderLayout og du vil have JTabbedPane * ind midt i JFramet. */ frame.pack(); frame.show(); } }
public class Spm3 extends JPanel implements ActionListener { private JFrame frame; private JPanel panelmain, panel1, panel2, panel3, panel4;
private JButton søg, slut; //trykknapper til hhv. at søge i databasen og afslutte private JTextField vognnr, dato; //tekstfelter til hhv. vognnr og dato private JTextArea resultat; //tekst felt til at udskrive resultat private int WIDTH = 210, HEIGHT = 170; private String resultatUd; // private DataBase database; // private Connection con; //databaseforbindelses-objektet
public Spm3(Connection con, JFrame fr)
//konstruktør, sætter vinduet op { // this.con= con; //overfør den modtagne databaseforbindelse
// database = new DataBase(con);
frame = fr; /** * Tilføjet BoxLayout til "this", som er et JPanel, du extender jo JPanel. */ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); //vælg layoutmanageren 'FlowLayout'
resultat = new JTextArea(10, 45);
JLabel input1 = new JLabel("Indtast vognummer"); //skriv ledeteksten 'Vognnr' vognnr= new JTextField(10); vognnr.addActionListener(this); //definer og tilføj tekstfeltet vognnr
JLabel input2 = new JLabel("Indtast dato"); dato= new JTextField(10); dato.addActionListener(this);
søg= new JButton("Søg"); //definer og tilføj søg-knappen
søg.addActionListener(this); //registrer søg-knappen, så tryk på //den kan opfanges
slut= new JButton("Afslut"); //definer og tilføj slut-knappen
slut.addActionListener(this); //registrer slut-knappen, så tryk på den kan opfanges
//Panel til søg vognnr og dato panel1 = new JPanel(); panel1. setLayout(new FlowLayout(FlowLayout.LEFT)); panel1.setBorder(new javax.swing.border.TitledBorder("Spørgsmål 3"));
//Panel til textArea panel2 = new JPanel(); panel2. setLayout(new FlowLayout(FlowLayout.LEFT)); panel2.setBorder(new javax.swing.border.TitledBorder("Resultat"));
//Panel til afslut knap panel3 = new JPanel(); panel3. setLayout(new FlowLayout(FlowLayout.LEFT));
/** * Tilføjet dit JTextArea til et JScrollPane, så det kan scrolle. Det er god kotume at gøre :) */ panel2.add(new JScrollPane(resultat));
panel3.add(slut);
/** * Jeg har helt fjernet "mainpanel", da du bare kan bruge "this", som er et JPanel * du extender jo JPanel. * Jeg adder bare de tre komponenter på BoxLayoutet, og den lægger dem under hinanden. */ add(panel1); add(panel2); add(panel3); /** * Dem skal du ikke kalde! Dit JFrame skal ikke kaldes fra andre steder. Når du "packer" det * bliver det lille, da alle komponenter krympes til min. størrelse. * Du skal heller ikke kalde show() herfra, du gør det allerede fra TaxaBagger.java */ // frame.pack(); // frame.show(); }
public void actionPerformed(ActionEvent e) //metode, der kaldes automatisk, når brugeren trykker på én af de registrerede //trykknapper (søg eller slut). { // if (e.getSource() == vognnr || e.getSource() == dato || e.getSource() == søg) // { // try // { // resultatUd=database.udskrivspm3a(vognnr.getText(), dato.getText()); // resultat.setText(resultatUd); // } // catch(Exception ex){System.out.println(ex);} // } // else if (e.getSource()==slut) //ellers hvis det var slut-knappen // { // try // { // con.close(); //nedlæg forbindelsen til myDB // } // catch (Exception ex){System.out.println(ex);} // System.exit(0); //afslut // } } }
Det knusende problem var at du fra Spm3.java kaldte frame.getContentPane().add(panelMain); Hvilket resulterer i at du lægger dit JPanel ovenpå det JTabbedPane du lige har tilføjet. Du tilføjer jo allerede Spm3 panelet til JTabbedPane, så du skal til JFrame kun tiføjet JTabbadPane :)
Dette er ikke godt. Du giver JTextArea'et en fast størrelse. Så vil det ikke følge med LayoutManageren når du resizer framet. // nix: resultat = new JTextArea(10,45); // gør i stedet: resultat = new JTextArea();
Er bare det bedste Layout, når du kun har en komponent, der bare skal fylde hele panelet. // nix: panel2. setLayout(new FlowLayout(FlowLayout.LEFT)); // gør i stedet: panel2.setLayout(new BorderLayout());
Fordi du i stedet tilføjer til et panel med BorderLayout, skal du angive hvor på panelet det skal tilføjes (WEST, NORTH, CENTER eller SOUTH) // nix: panel2.add(new JScrollPane(resultat)); // gør i stedet: panel2.add(new JScrollPane(resultat), BorderLayout.CENTER);
Jeg har bare læst og prøvet og læst og prøvet. Et er nemlig at lave GUI i Java, noget HELT andet er at lave god GUI i Java. Swing er bygget til at du kan designe helt vanvittigt gode brugergrænseflader, hvis du bruger det rigtigt og hvis du udnytter de designmønstre der ligger i det.
Jeg har gjort meget brug af APIen, og det gælder om at forsøge at lave tingene rigtigt fra start, så man ikke bliver for vant til at lave tingene forkert da det så bliver meget sværere at skifte.
Hver gang man skal afprøve en ny komponent, feks. JTable. Så læs APIen og the Java Tutorial: http://java.sun.com/docs/books/tutorial/uiswing/TOC.html og gør så hvad de gør. Kom i gang med at lave egne modeller til Swing komponenter, forstå at specialisere Swing komponenter.. osv.
Jeg synes afgjort Swing er noget af det sværeste i Java. Det kræver meget øvelse at blive god til det, men når man så gør er det det bedste programmeringssprog til at designe brugergrænseflader i, synes jeg :)
Det kan være tricky at bruge Layoutmanagers, men sørg for IKKE at følge denne cyklus: - Lær kun de mest simple layout-managere at kende - Bliv irriteret over hvor "dumme" de er - Slå alle layout-managere fra - Placer alt manuelt med pixels nøjagtighed (null layout!¤%&¤") - Bliv træt af den tid det tager (det tager en evighed at justere) - Brug en GUI-Builder (ALDRIG I LIVET!!) - Bliv frustreret over ikke at kunne få det til at fungere sammen med sit program - Begynde at programmere Visual Basic - Lide hjernedøden :-)
Et par hints til layoutmanagers kan være: - Dit hoved JFrame skal altid have BorderLayout. Enhver applikation du kigger på i Windows og andre operativsystemer indeholder komponeneter i den layout form, hvis du lægger mærke til det. (panel på venstre side. Stort panel midt på, og små paneler øvers(JMenu osv). Tænk bla. på Outlook: Et træ til venstre( BorderLayout.WEST), et stort panel i midten( BorderLayout.CENTER) - som består af 2 mindre paneler, hvor det ene indeholder en tabel og det andet et tekstfelt.
- Brug den simplest mulige LayoutManager du kan slippe afsted med og lær at se hvornår det måske er bedre at flytte det ud på to paneler i stedet. Du kan komme meget langt med paneler med BoxLayout og FlowLayout. Lær som en af de sidste LayoutManagers, GridBagLayout, som er rimelig kompleks.
- Brug www.docjava.dk til at lære om layouts, under sektionen Grafiske Brugergrænseflader.
- Lær at tegne brugergrænsefladen på et stykke papir og forestil dig hvordan du kan gøre det i Java.
- Øv dig, og hver gang du får en ide til noget du gerne vil lave, så sæt dig ned og lav det. Det bliver sjovere og sjovere jo bedre du bliver til det. Brugergrænsefladen er jo fra brugerens synspunkt vigtigste i et program, da det er det eneste han/hun ser. Vedkommende ser jo ikke om du har brugt 20 GoF mønstre i dit persistenslag, vel?
Lav noget simpelt --> få succesoplevelse --> lav noget lidt mere avanceret --> få succesoplevelse osv.. men spring ikke for langt frem ad gange, så bliver det uoverskueligt.
Har du iøvrigt en forklaring på hvorfor Java's GUI er så relativ langsom? Det er vist ikke helt forkelt, hvis man siger at det er den langsommeste GUI i alle sprog jeg kender.
Er det fordi at det skal kunne køre på alle platforme?
Eller har designerne bare ikke tænkt sig ordenlig om! (Det er jo ingen hemmeligehed at de ikke var for heldige med AWT)
Well.. jeg vil ikke sige Swing er _langsomt_... jeg har set GUIer i C# der kører ringere. Du skal huske på at al Swing afvikles og emuleres i JVM, der er næsten ingen native afvikling af grafik og derved sænkes hastigheden. Hvis Java kun skulle køre på Windows feks., så var det ikke noget problem bare at hooke ned i ren Windows grafik, men grafikken skal jo se ens ud i Linux, Unix og Windows.
JVM udfører når den tegner et JFrame ca. følgende: 1. Hvilken form skal jeg tegne? 2. Hvilket operativsystem er jeg på? 3. Tegn det jeg kan i native 4. emuler det jeg ikke kan tegne
Det er jo appletter, det gider jeg ikke bøvle med :) Jeg afskyr apletter og arbejder hellere med Web Start/Swing.
Ellers tak for tippet :)
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.