Gyakorlati alapok IV.
Végre ablakozunk! (AWT, Swing, JavaFX)
Tanulói jelenlétek összeszámlálása (Button + Textfield + filekezelés)
Ebben a fejezetben a
textfield-objektum (A
textfield alaptulajdonságai) szokásos felhasználását célozzuk meg,
de a funkciókat külső
file-műveletekkel
is kiegészítjük.
Adott egy naplo.txt nevű állomány…
...amely tanulók félévi jelenléti-hiányzási adatait tartalmazza. A tanuló neve
mellett lévő, szisztematikusan elhelyezett szimbólumok a következő státuszokat
jelentik:
-
0 – jelen volt
-
X - igazolt hiányzás
-
I - igazolatlan hiányzás
-
N - nem volt óra
Például:
-
Galagonya Alfonz OXXXXXX
A feladat 1. körben, hogy az
állományból szűrjűk le a keresett tanuló teljes jelenléti státuszát.
Ugyanakkor alapszinten az adatbevitelt validálnunk is kell, illetve
emlékezzünk a
Filekezelés című fejezetcsomagban tanultakra, amely szerint a filekezelés
-lévén külső, “veszélyes” művelet-, kötelező kivételkezeléssel is párosul.
A kötelezőségeken felül a feladatot meg lehet oldani egyszerűen és bonyolultan
is. Az utóbbi az objektumorientált alapelvek nagyon következetes és szigorú
követését jelenti, például ha minden magasabb szintű funkció külön osztályba
kerül. A megoldás 1. részében ettől most el fogunk tekinteni és marad az
egyszerűbb megoldás, amely során szinte minden funkciót a
buttonAction() függvényben dolgozunk ki.
Először nézzük meg az alapszintű validálási szabányokat!
Amint az már említésre került, az állomány megnyitását kötelező
kivételkezeléssel kell bebiztosítanunk (try-catch).
Ezt könnyű megtennünk a catch() blokkokba tett
üzenetablakok segítségével. Az üzenetek -az elkapott kivételek, hibák
jellegéből következtetve-, lehetnek különbözők is:
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(frame, "A fájl nem található!");
} catch (IOException ioe) {
JOptionPane.showMessageDialog(frame, "Fájlkezelési vagy egyéb hiba!");
Mindenképpen le kell védenünk a bemeneti szövegmezőket. Alapszinten azt
akadályozzuk meg, hogy a felhasználó kitöltetlenül hagyja azokat, bár ha
rosszul gépeli be a file elérési útját, úgyis kap
egy A fájl nem található! feliratú üzenetablakot:
if(textPath.getText().equals("")) {
JOptionPane.showMessageDialog(frame, "Üres fájl elérési
út!");
return;
}
if(textSearch.getText().equals("")) {
JOptionPane.showMessageDialog(frame, "Üres keresési mező!");
return;
}
Nagyjából ugyanez érvényes a névkeresési szövegmezőre, kivéve:
-
nincs lekezelve az a hiba, ha a hiányzó neve nincs benne a fájlban,
-
ha a beírt szöveg csak hasonlít a névre (hiszen a névazonosításhoz felhasznált függvény csak a contains() volt).
Ezen 2 probléma lekezelése a projekt 1. körös megalkotása szempontjából nem volt lényeges, ráadásként pedig bonyolítani is kellett volna hozzá a kódot:
-
vagy külön filekezelő beolvasásban ellenőrizni a név meglétét,
-
vagy a beolvasás adatait külön objektumokba mentve azokon az ellenőrzést végrehajtani,
-
az is lehetséges, hogy az ellenőrzést “röptében” is meg lehet oldani, de persze bonyolultabban.
A file beolvasásakor egy hátulról
induló for ciklus Integer típusú számlálókba
osztályozza a jelenléti adatokat:
while(line != null) {
if(line.contains(textSearch.getText())) {
System.out.println(line); //kiírás
konzolra tesztelésre
for(int i = line.length()-1; i >= 11;
i--) {
char
character = line.charAt(i);
switch
(character) {
case ('O'): count_O++; break;
case ('X'): count_X++; break;
case ('I'): count_I++; break;
case ('N'): count_N++; break;
}
}
}
Ezután a számlálók tartalmai konvertálásra kerülnek
String adattípusba a végső megjelenítéshez. Ennek objektuma a már jól
ismert üzenetablak, amelynek tartalmát megjelenítés előtt szépen
megformázhatjuk:
String stringCount_O = Integer.toString(count_O);
String stringCount_X = Integer.toString(count_X);
String stringCount_I = Integer.toString(count_I);
String stringCount_N = Integer.toString(count_N);
String stringResult = textSearch.getText()
+ " jelen volt " + stringCount_O + " órán,\n"
+ "igazoltan hiányzott " + stringCount_X + " órán,\n"
+ "igazolatlanul hiányzott " + stringCount_I + " órán,\n"
+ "nem volt jelen " + stringCount_N + " órán.";
JOptionPane.showMessageDialog(frame, stringResult);
Mindezután kicsit inicializálunk, alaphelyzetbe állítunk, hiszen lehet, hogy a
felhasználó az applikációban nemcsak egyszer kíván keresni...
textPath.setText("");
textSearch.setText("");
count_O = 0;
count_X = 0;
count_I = 0;
count_N = 0;
System.out.println();
return;
...majd már csak kivételkezelés és végső lezárások következnek:
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(frame, "A fájl nem
található!");
textPath.setText("");
textSearch.setText("");
return;
} catch (IOException ioe) {
JOptionPane.showMessageDialog(frame, "Fájlkezelési vagy egyéb
hiba!");
ioe.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException ioe) {
JOptionPane.showMessageDialog(frame,
"Fájlkezelési vagy egyéb hiba!");
ioe.printStackTrace();
}
}
}
}
Nézzük meg a futtatható Java-kódot:
Main.java
public class Main {
public static void main(String[] args) {
Window window = new Window();
}
}
Window.java
import
java.awt.*;
import java.io.*;
import javax.swing.*;
class Window extends JFrame {
JFrame frame = new JFrame();
JButton button = new JButton("Keress!");
JLabel labelPath = new JLabel();
JLabel labelSearch = new JLabel();
JTextField textPath = new JTextField();
JTextField textSearch = new JTextField();
Window() {
super();
labelPath.setBounds(100, 50, 200, 25);
labelPath.setFont(new Font("Serif", Font.PLAIN, 12));
labelPath.setText("Elérési út + fájlnév (pl.
C:\\\\naplo.txt)");
textPath.setBounds(100, 75, 200, 25);
labelSearch.setBounds(100, 100, 200, 25);
labelSearch.setFont(new Font("Serif", Font.PLAIN, 16));
labelSearch.setText("Névkeresés");
textSearch.setBounds(100, 125, 200, 25);
button.setBounds(100, 175, 200, 30);
button.addActionListener(event -> buttonAction());
frame.add(button);
frame.add(labelPath);
frame.add(labelSearch);
frame.add(textPath);
frame.add(textSearch);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 325);
frame.setTitle("PJP - Penzes Java Programming");
Center center = new Center();
center.setCenter(frame);
frame.setLayout(null);
frame.setVisible(true);
}
private void buttonAction() {
if(textPath.getText().equals("")) {
JOptionPane.showMessageDialog(frame,
"Üres fájl elérési út!");
return;
}
if(textSearch.getText().equals("")) {
JOptionPane.showMessageDialog(frame,
"Üres keresési mező!");
return;
}
//tesztelésre, a beviteli mezők tartalmának
kiírása konzolra
// System.out.println(textPath.getText());
// System.out.println(textSearch.getText());
/* 0 - jelen
* X - igazolt hiányzás
* I - igazolatlan hiányzás
* N - nem volt óra
* E:\\naplo.txt
* Papaja Inez
* Alma Hedvig
* Galagonya Alfonz
* E:\\naplo.txt
*/
FileReader reader = null;
try {
reader = new
FileReader(textPath.getText());
BufferedReader bufferedReader = new
BufferedReader(reader);
String line =
bufferedReader.readLine();
int count_O = 0;
int count_X = 0;
int count_I = 0;
int count_N = 0;
while(line != null) {
if(line.contains(textSearch.getText())) {
System.out.println(line); //kiírás konzolra tesztelésre
for(int i = line.length()-1; i >= 11; i--) {
char character = line.charAt(i);
switch (character) {
case ('O'): count_O++; break;
case ('X'): count_X++; break;
case ('I'): count_I++; break;
case ('N'): count_N++; break;
}
}
}
line = bufferedReader.readLine();
}
String stringCount_O = Integer.toString(count_O);
String stringCount_X = Integer.toString(count_X);
String stringCount_I = Integer.toString(count_I);
String stringCount_N = Integer.toString(count_N);
String stringResult = textSearch.getText()
+ " jelen volt " + stringCount_O + " órán,\n"
+ "igazoltan hiányzott " + stringCount_X + " órán,\n"
+ "igazolatlanul hiányzott " + stringCount_I + " órán,\n"
+ "nem volt jelen " + stringCount_N + " órán.";
JOptionPane.showMessageDialog(frame, stringResult);
textPath.setText("");
textSearch.setText("");
count_O = 0;
count_X = 0;
count_I = 0;
count_N = 0;
System.out.println();
return;
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(frame,
"A fájl nem található!");
textPath.setText("");
textSearch.setText("");
return;
} catch (IOException ioe) {
JOptionPane.showMessageDialog(frame,
"Fájlkezelési vagy egyéb hiba!");
ioe.printStackTrace();
} finally {
try {
if (reader !=
null) {
reader.close();
}
} catch (IOException ioe) {
JOptionPane.showMessageDialog(frame,
"Fájlkezelési vagy egyéb hiba!");
ioe.printStackTrace();
}
}
}
}
Center.java
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;
public class Center {
void setCenter(JFrame frame) {
Point center =
GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
int x = (int) center.getX() - (frame.getWidth() / 2);
int y = (int) center.getY() - (frame.getHeight() / 2);
Point ablakCenter = new Point(x, y);
frame.setLocation(ablakCenter);
}
}
Végeredmény (a monitor közepén / felbontástól függetlenül/):
A projektből következő további feladatok a következők lehetnek:
-
oldjuk meg a fent említett névvalidálást,
-
tegyük a filekezelést külön osztályba,
-
tegyük a kivételkezelést külön osztályba,
-
a naplo.txt állományba belepillantván észrevehetünk további adatokat is, ezek egyedi azonosítóval (#) kezdődő dátumok (például # 01 15, amely január 15. jelent). Valamilyen módon építsük be a dátumot is a kiértékelésbe!
Ezek legyenek a Tisztelt Olvasó házi feladatai!