B
ByeBye 148134
Hallo zusammen,
ich habe nun das Forum durchforstet, fand aber keine Lösung, darum das neue Thema.
Kurzes Briefing:
Ich habe ein Programm geschrieben, das sämtliche Bilder einer Webseite in einen Ordner speichert.
Ablauf:
Die Klassen:
PicDownloader: Hier ist keine Logik vorhanden, lediglich das Frame, dessen Aufbau und Actionhandling der Komponenten
URLScanner = Hier ist die Logik enthalten, zu Beginn wird ein Objekt davon erstellt.
Hier der relevante Teil des PicDownloader:
Und hier nun der relevante Teil der Logikklasse
Der Fehler - bzw. das Problem, bei dem ich nicht weiterkomme ist bei der "TODO" Kennzeichnung. Eigentlich sollte das Feld infofeld bei jedem Schleifendurchlauf geupdatet werden, so dass man sieht, welches Bild gerade gespeichert wurde. Tatsächlich ist es aber so, dass sämtliche Bilder gespeichert werden und erst wenn dies beendet ist, wird der Inhalt von JTextArea aktualisiert. Das erweckt bei dem Speichervorgang natürlich den Eindruck, dass Programm tut nichts oder hat sich aufgehängt.
Probiert habe ich schon folgendes:
Wobei ich mir bei letzterem Punkt nicht sicher bin, aber nicht weiß, wo der separate Thread hinmuss und was dieser tun soll: Speichern oder das infoFeld updaten?
Ich hoffe, ihr könnt mir bei meinem Problem helfen!
Viele Grüße und schonmal ein schönes Wochenende,
CrazyBread
ich habe nun das Forum durchforstet, fand aber keine Lösung, darum das neue Thema.
Kurzes Briefing:
Ich habe ein Programm geschrieben, das sämtliche Bilder einer Webseite in einen Ordner speichert.
Ablauf:
- HTML Quelltext wird eingelesen
- Quelltext wird nach "href" Tags durchsucht, jeder Link wird in einer Arraylist gespeichert
- Mittels Schleife wird durch das Array gegangen und jedes Bild gespeichert
Die Klassen:
PicDownloader: Hier ist keine Logik vorhanden, lediglich das Frame, dessen Aufbau und Actionhandling der Komponenten
URLScanner = Hier ist die Logik enthalten, zu Beginn wird ein Objekt davon erstellt.
Hier der relevante Teil des PicDownloader:
Code:
public class FourChanPicDownloader {
//Texte
final String URL_INVALID="Bitte geben Sie eine gültige URL ein!\nBeispiel: https://boards.4chan.org/s/res/13512782";
final String FOUND_PICS="Es wurden [picSum] Bilder gefunden.\nKlicken Sie auf den Button unten, um den Download zu starten.";
// GUI Komponenten
JFrame frame;
JLabel label;
JTextField urlEingabe;
JButton bilderHolen;
JButton speichern;
JPanel hauptPanel;
JTextArea infoFeld;
// Variablen
ArrayList<String> links = new ArrayList<String>();
URLScanner scanner = new URLScanner();
public static void main(String[] args) {
new FourChanPicDownloader().go();
}
public void go() {
frame = new JFrame("4chan Pic Downloader");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(350, 300);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
urlEingabe = new JTextField(30);
infoFeld = new JTextArea(5, 30);
infoFeld.setEditable(true);
infoFeld.setText("Bitte URL kopieren und Bilder holen");
JScrollPane scroller = new JScrollPane(infoFeld);
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
bilderHolen = new JButton("Anzahl Bilder holen");
bilderHolen.addActionListener(new BilderHolenListener());
speichern = new JButton("Bilder speichern");
speichern.addActionListener(new SpeichernListener());
speichern.setEnabled(false);
hauptPanel = new JPanel();
//hauptPanel.setLayout(new BoxLayout(hauptPanel, BoxLayout.Y_AXIS));
hauptPanel.add(urlEingabe);
hauptPanel.add(bilderHolen);
hauptPanel.add(scroller);
hauptPanel.add(speichern);
frame.add(hauptPanel);
frame.setVisible(true);
}
public class BilderHolenListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
if (urlEingabe.getText().isEmpty()) {
infoFeld.setText(URL_INVALID);
} else {
links = scanner.getLinks(urlEingabe.getText().trim());
infoFeld.setText(FOUND_PICS.replace("[picSum]", String.valueOf(links.size())));
speichern.setEnabled(true);
}
}
}
public class SpeichernListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
scanner.savePicsInDir(links, frame, infoFeld);
}
}
}
Und hier nun der relevante Teil der Logikklasse
Code:
public class URLScanner {
public void savePicsInDir(ArrayList<String> pics, JFrame frame, JTextArea infoFeld){
JFileChooser fchooser = new JFileChooser();
infoFeld.setText("");
//Ein Ordner muss als Speicherort ausgewählt werden
fchooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fchooser.showSaveDialog(frame);
try{
int counter = 1;
int anzahlBilder = pics.size();
for (String aktuellesBild:pics){
String fileName = convert(counter, 4);
File file = new File(fchooser.getSelectedFile().getAbsolutePath()+"\\"+fileName+"."+getFileEnding(aktuellesBild));
// aus dem String eine URL machen
URL url = new URL(aktuellesBild);
// eine HTTPS-Connection erstellen
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
// einen Browser "nachahmen"
con.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)");
FileOutputStream out = new FileOutputStream(file);
InputStream in = con.getInputStream();
int n;
byte[] buf = new byte[4096];
while( (n = in.read(buf)) > 0)
{
out.write(buf, 0, n);
}
in.close();
out.close();
infoFeld.append("Bild "+counter+" von "+anzahlBilder+" gespeichert.\n");
//TODO: Feld wird nicht nach jedem Speichern geupdatet...
counter++;
}
System.out.println("Speichern erfolgreich");
} catch (Exception e){
e.printStackTrace();
}
}
}
Der Fehler - bzw. das Problem, bei dem ich nicht weiterkomme ist bei der "TODO" Kennzeichnung. Eigentlich sollte das Feld infofeld bei jedem Schleifendurchlauf geupdatet werden, so dass man sieht, welches Bild gerade gespeichert wurde. Tatsächlich ist es aber so, dass sämtliche Bilder gespeichert werden und erst wenn dies beendet ist, wird der Inhalt von JTextArea aktualisiert. Das erweckt bei dem Speichervorgang natürlich den Eindruck, dass Programm tut nichts oder hat sich aufgehängt.
Probiert habe ich schon folgendes:
- Sämtliche repaint() oder revalidate() Varianten
- Einen eigenen Thread für das Updaten der JTextArea
Wobei ich mir bei letzterem Punkt nicht sicher bin, aber nicht weiß, wo der separate Thread hinmuss und was dieser tun soll: Speichern oder das infoFeld updaten?
Ich hoffe, ihr könnt mir bei meinem Problem helfen!
Viele Grüße und schonmal ein schönes Wochenende,
CrazyBread