簡易Webブラウザを作る
昔の記事だけど、Javaでかなり本格的なWebブラウザを作れるらしいので、私も作ってみる。
ブラウザを表示させる
参考元のソースで、「戻る、進むを実装してみる(前のページ、次のページ)」をまずは写経する。
(その時に、ファイル名/パッケージ名は任意に変えている。)
この時に、Mavenを使ってJavaFXを読み込もうとして少し苦労した。(わかってしまえば難しいことではなかった。。。)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>webbrowser</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2/</url>
</repository>
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-web -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>15.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<configuration>
<jlinkImageName>hellobrowser</jlinkImageName>
<launcher>launcher</launcher>
<mainClass>xyz.osamusasa.browser.MainApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
実行結果
タブ機能を追加する
タブを新規に追加する機能
タブ機能はjavafx.scene.control.TabPaneを使うことで簡単に実装できる。
mainPane.fxml(抜粋・変更前)
<center>
<!-- 画面中央のWeb画面表示 -->
<WebView fx:id="webView"></WebView>
</center>
mainPane.fxml(抜粋・変更後)
<center>
<TabPane>
<Tab>
<!-- 画面中央のWeb画面表示 -->
<WebView fx:id="webView"></WebView>
</Tab>
</TabPane>
</center>
実行結果
タブが表示されている(タブを消す×ボタンが表示されているだけだが。。)
他の必要な機能を実装する
これをベースに以下の機能を追加した。
- 新規タブボタン
- 戻るボタン・進むボタンを現在開いているタブに対して実行する
- URLがロードされるとそのページのタイトルをタブの名称に設定する。
Controller.java
package xyz.osamusasa.browser;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.scene.web.WebView;
import java.util.Optional;
public class Controller {
@FXML private TextField addressBar;
@FXML private TabPane tabPane;
/**
* 初期化処理(自動呼出し)
*
* initialize()メソッドは自動呼出しの対象となる
*/
public void initialize() {
loadNewTab("https://www.google.co.jp/");
}
/**
* アドレスバーでEnter
*
* @param e ActionEvent
*/
public void onAddressBarEvent(KeyEvent e) {
switch(e.getCode()) {
case ENTER:load(addressBar.getText());break;
default:
break;
}
}
/**
* 戻るボタン
*
* @param e ActionEvent
*/
public void onBack(ActionEvent e) {
currentWebView().ifPresent(webView -> {
WebEngine engine = webView.getEngine();
WebHistory history = engine.getHistory();
if ( history.getCurrentIndex() > 0 ) history.go(-1);
});
}
/**
* 進むボタン
*
* @param e ActionEvent
*/
public void onNext(ActionEvent e) {
currentWebView().ifPresent(webView -> {
WebEngine engine = webView.getEngine();
WebHistory history = engine.getHistory();
if (history.getCurrentIndex() < history.getEntries().size() - 1) history.go(1);
});
}
/**
* 新規タブボタン
*
* @param e ActionEvent
*/
public void onNewTab(ActionEvent e) {
loadNewTab("https://www.google.co.jp/");
}
/**
* URLロード
*
* @param search URL
*/
public void load(String search) {
final String searchStr;
if ( !search.matches("^https{0,1}://.+") ) {
//httpじゃないならgoogle検索を実行
searchStr = "https://www.google.co.jp/search?q="+search;
} else {
searchStr = search;
}
currentWebView().ifPresentOrElse(
webView -> webView.getEngine().load(searchStr),
() -> loadNewTab(searchStr)
);
}
/**
* 新規タブでURLロード
*
* @param search URL
*/
private void loadNewTab(String search) {
// 新規タブ作成
Tab tab = new Tab(search);
WebView view = new WebView();
WebEngine engine = view.getEngine();
//ページロードイベントでアドレスバーの更新
engine.getLoadWorker().stateProperty().addListener(
(ov, oldState, newState) -> {
if (newState == State.SUCCEEDED) {
addressBar.setText(engine.getLocation());
tab.setText(engine.getTitle());
}
}
);
// URLロード
engine.load(search);
// 作成したタブを追加
tab.setContent(view);
tabPane.getTabs().add(tab);
// 新規タブを表示
tabPane.getSelectionModel().select(tab);
}
/**
* 現在選択されているタブのWebViewを返す
*
* @return 選択されているWebView
*/
private Optional<WebView> currentWebView() {
return Optional.ofNullable(tabPane.getSelectionModel().getSelectedItem())
.map(Tab::getContent)
.filter(n -> n instanceof WebView)
.map(n -> (WebView)n);
}
}
mainPane.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TabPane?>
<!-- fx:controllerで関連付けるコントローラクラスを指定 -->
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.osamusasa.browser.Controller">
<top>
<!-- 画面ヘッダーの表示 -->
<BorderPane styleClass="topView">
<left>
<FlowPane prefWidth="100">
<Button onAction="#onBack" text="戻る"></Button>
<Button onAction="#onNext" text="進む"></Button>
</FlowPane>
</left>
<center>
<TextField fx:id="addressBar" text="" onKeyPressed="#onAddressBarEvent" ></TextField>
</center>
<right>
<FlowPane prefWidth="100">
<Button onAction="#onNewTab" text="+"></Button>
</FlowPane>
</right>
</BorderPane>
</top>
<center>
<TabPane fx:id="tabPane">
</TabPane>
</center>
</BorderPane>
実行結果
(実行した日付がバレてしまう。。。)
ブックマーク機能
ブックマークの表示方法はツールバーやサイドバー、別タブ、メニューなど様々あるが、今回はfirefox流に別ウィンドウで表示させるものを実装する。
実行結果
- ブックマークを追加する
- ブックマークからWebページを開く
WIP...
思い出したら続き書く