解决方案 »
- native方法的源码在哪里看
- Java写的一个弹出式菜单,可是为啥没结果呢,编译没出错啊
- 关于 建包的问题
- tools.jar和dt.jar的问题
- No suitable driver是怎么回事?用了很多种方法都不行
- 接口(哪位老大讲讲咯!)
- 急,请问怎样清掉先前留在socket.getInputStream()里面的东西?
- 大家帮帮我完成作业
- 谁能肯定在 Java 小程序中不能通过 Socket 在客户机与服务器之间通讯?
- 请问JAVA如何编写多线程共享一个变量?注意是不同的构造函数做出的线程。
- Java socket I/O流问题
- 用java Runtime .exec启动并matlab 文件,参数如何传递
(获得焦点效果)(失去焦点后的效果)(鼠标移到Container内容面板上后显示的效果)最后说下自己的感想:
1、现在Java界面编程真的不是首选。可插拔式的Look and feel不论基于Basic还是Metal编写繁琐,开发周期长。后来1.7推出的Synth基于XML导入式概念虽然新颖,但是对于Components Specific Properties的支持不够例如对于JTable的Properties支持很少导致可定制性降低。基于Nimbus编写的话,首先运行效率不如Metal,然后重绘每个Component也很麻烦,用图片做背景需要九宫格技术的支持。无论如何,Look and feel由于Java内部本身的限制,提供定制的范围确实有限,有些东西你customize不了,因为它没有提供那样的接口。
2、但是简单的界面编写如对动态效果没什么要求,对Desktop集成没什么要求(Java需要调用JNI来集成一些桌面特性,如WIn7任务栏图片的进度加载显示,还有比如SystemTray也只能用AWT的PopupMenu导致没法定制出和QQ、迅雷等一样的托盘效果),使用Swing还是可以的,Swing的优势也就在于跨平台性好,优于SWT。建议简单界面能使用Swing的还是不要使用SWT,对于简单界面,自己编写的L&F也搓搓有余了。
3、对于想要Charts、多媒体支持、动画效果、滤镜支持、触摸事件感应处理等富Internet绚丽界面的追求的话,建议选择用JavaFX,可插拔式用外部链接的CSS代替,一般界面的编写可以用FXML,逻辑处理用Java语言或者JavaScript。这样结构化很明显,也很现代化(参见MVC设计模式)。但是JavaFX目前Bug还是很多,很多功能不完善,比如SystemTray没有支持,Print打印功能也是在未来Java8中绑定,但是对于打印表格table似乎还没有支持(我不大确定,因为我只是初步的看了一下,还没有深入研究)。但其UI组件未来会逐渐增多。
4、目前的话Java界面编写还是JavaFX比较有前途,但是就目前的JavaFX而言似乎没有什么明显的竞争力,只能期待以后的发展了。
5、建议还是用目前主流的软件编写工具(例如论坛同志所说的“要做Desktop GUI 推荐QT C++,ui tool 和 qml 非常易用强大。”)。想要在Windows下使用的话,还是尽量调用本地化的windows API。
6、用数据库相结合的小软件编写,Java还是不错的。内置的JavaDB就不错,MySQL以及Microsoft Database也有很多开发案例,使用Oracle大型数据库就更不用说了。Swing给我印象最深的就是绘图机制十分强大,至少在引入Android的NinePatch技术上领先JavaFX(如果有同志知道如何在JavaFX上使用类似于Android的NinePatch技术的,非常感谢告知我),一定要深刻理解java界面的绘图机制。像背景图片什么绘制是很简单的,至于图像的缩放,运用ImageOP写个缩放的,或者模糊效果等等,在Java 界面代码中用paintComponent()方法来定制背景图片的可以根据addComponentListener()中的componentResize()来缩放就可以了(使用repaint())。绘制Border或者Button的背景,图片最好使用九宫格技术,防止图片拉伸失真。在Synth中,它自带把图片分为9块的技术,使用起来十分方便,然而不如Android的NinePatch技术,因为她不仅可以分图片为9块,而且可以根据需要分为若干块我非常欣赏。最近正在写一套的基于Nimbus的lnf(当然使用了Android的NinePatch技术),感觉还不错,推荐诸位试一下,我顺带研究JavaFX,觉得前途还是有的,因为Oracle计划不断随着Java8,9,10的推出更新、支持JavaFX。
<?xml version="1.0" encoding="UTF-8"?>
<?language javascript?><?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.Scene?><!-- "id" serves to CSS, "fx:id" serves to controller(java or js) and CSS -->
<Scene xmlns:fx="http://javafx.com/fxml" width="300" height="275">
<fx:script source="info.js"/>
<GridPane styleClass="grid-pane">
<Text styleClass="welcome-text" text="%welcome"
GridPane.columnIndex="0" GridPane.rowIndex="0"
GridPane.columnSpan="2"/>
<Label text="%userName"
GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField
GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="%password"
GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<PasswordField
GridPane.columnIndex="1" GridPane.rowIndex="2"
onAction="#handlePFAction"/>
<HBox styleClass="h-box"
GridPane.columnIndex="1" GridPane.rowIndex="4">
<Button fx:id="submitButton" text="%signIn"
onAction="#handleSubmitButtonAction"/>
</HBox>
<Text fx:id="actionTarget"
GridPane.columnIndex="1" GridPane.rowIndex="6"/>
<!-- <gridLinesVisible>true</gridLinesVisible> -->
</GridPane>
<fx:script>
var System = java.lang.System;
var message = "this is the end of XML contents";
System.out.println(message);
</fx:script>
</Scene>
/* applies to the root node of Scene, it can specify global common properties */
.root {
-fx-background-image: url("background.jpg");
}.label {
-fx-font-size: 12px;
-fx-font-weight: bold;
-fx-text-fill: #333333;
-fx-effect: dropshadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 );
}.button {
-fx-text-fill: white;
-fx-font-family: "Arial Narrow";
-fx-font-weight: bold;
-fx-background-color: linear-gradient(#61a2b1, #2A5058);
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 5,0,0,1 );
}.button:hover, .button:armed { /* pseudo-classes */
-fx-background-color: linear-gradient(#2A5058, #61a2b1);
}.grid-pane {
-fx-hgap: 10;
-fx-vgap: 10;
-fx-alignment: center;
-fx-grid-lines-visible: false;
-fx-padding: 25 25 10 25;
}.h-box {
-fx-spacing: 10;
-fx-alignment: bottom-right;
}.welcome-text {
-fx-font-size: 32px;
-fx-font-family: "Arial Black";
-fx-fill: #818181;
-fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.7), 6,0,0,2 );
}#actionTarget {
-fx-fill: FIREBRICK;
-fx-font-weight: bold;
-fx-effect: dropshadow( gaussian, rgba(255,255,255,0.5), 0,0,0,1 );
}
// Provide some necessary infos
importClass(java.lang.System);
var info = "starts loading of XML file";
System.out.println(info);
# This is a default resource bundle when a searching in getBundle() with the
# given locale fails.
welcome=Welcome
userName=User Name:
password=Password:
signIn=Sign In
actionTarget=Sign in button pressed
# This is a Chinese resource bundle. It is encoded by ISO-8859-1. In this case,
# characters that cannot be directly represented in ISO-8859-1 encoding can be
# written using Unicode escapes as defined in section 3.3 of The Java\u2122
# Language Specification.
welcome=\u6B22\u8FCE
userName=\u7528\u6237\u540D\uFF1A
password=\u5BC6\u7801\uFF1A
signIn=\u767B\u9646
actionTarget=\u767B\u9646\u6309\u94AE\u88AB\u6309\u4E0B
# This is a en_US resource bundle.
welcome=Welcome
userName=User Name:
password=Password:
signIn=Sign In
actionTarget=Sign in button pressed
# This is a fr_FR resource bundle.
welcome=Bienvenue
userName=Identifiant:
password=Mot de Passe:
signIn=Se connecter
actionTarget=Bouton appuyé
package loginfxml;import java.net.URL;
import java.util.ResourceBundle;import javafx.animation.PauseTransition;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.text.Text;
import javafx.util.Duration;/**
* It is often preferable to define more complex application logic in a
* compiled, strongly-typed language such as Java. For example, some complex
* event handlers and any other application logic.
* <p>
* It implements an <code>Initializable</code> interface, which defines
* <code>an initialize()</code> method. It will be called once on an
* implementing controller when the contents of its associated document have
* been completely loaded. It allows the implementing class to perform any
* necessary post-processing on the content.
*
* @author HAN
*
*/
public class Controller implements Initializable {
// If the controller member fields or methods are private or protected, it
// should be annotated so as to be accessible to up. If they are public,
// the javafx.fxml.FXML annotation is not necessary.
@FXML
private Button submitButton; @FXML
private Text actionTarget;
private ResourceBundle resources;
@FXML
private void handlePFAction() {
PauseTransition pressTime = new PauseTransition(Duration.millis(220));
pressTime.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
submitButton.disarm();
submitButton.fire();
}
});
submitButton.arm();
pressTime.play();
}
@FXML
private void handleSubmitButtonAction() {
actionTarget.setText(resources.getString("actionTarget"));
} @Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("location: " + location);
System.out.println("resources: " + resources);
this.resources = resources;
System.out.println("to perform any necessary post-processing on the "
+ "content, which will be called once when the contents of "
+ "its associated document have been completely loaded");
// For example, to process lookup() method with the given CSS selector,
// which normally in java code should be placed after Stage.show(). Note
// that the button defined in FXML can not be invoked in Model java code
// file which is proven by my practice.
System.out.println("name of submit button: " + submitButton.getText());
System.out.println(submitButton.lookupAll(".button"));
Button button = (Button) submitButton.lookup(".button");
button.setText("Sign in");
System.out.println("new name of submit button: "
+ submitButton.getText());
}
}
package loginfxml;import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;public class Model extends Application {
public static void main(String[] args) {
launch(args);
} @Override
public void start(Stage stage) throws Exception {
Locale locale = getCurrentLocale();
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(Model.class.getResource("View.fxml"));
ResourceBundle resources = ResourceBundle.getBundle(
"loginfxml/MyResources", locale, Model.class.getClassLoader());
fxmlLoader.setResources(resources);
fxmlLoader.setController(new Controller());
Scene scene = (Scene) fxmlLoader.load();
scene.getStylesheets().add(
Model.class.getResource("login.css").toExternalForm());
stage.setTitle("Welcome FXML");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
} private Locale getCurrentLocale() {
Map<String, String> namedParams = getParameters().getNamed();
String languageParam = namedParams.get("language");
String countryParam = namedParams.get("country"); Locale locale = Locale.getDefault();
if (languageParam != null && languageParam.trim().length() > 0) {
if (countryParam != null && countryParam.trim().length() > 0) {
locale = new Locale(languageParam.trim(), countryParam.trim());
} else {
locale = new Locale(languageParam.trim());
}
}
return locale;
}
}所有资源下载链接:
View.fxml
login.css
info.js
MyResources.properties
MyResources_zh_CN.properties
MyResources_en_US.properties
MyResources_fr_FR.properties
Controller.java
Model.java运行结果(注:在命令行中设置语言包,或者在你的JNLP文件中设置以便Applet或者WebStart应用):
有些 basic ui 类有明显的设计缺陷,很多东西被硬编码,导致扩展功能比较困难……SwingLabs (SwingX) 的很多组件都没有加进 JDK ……据说 SwingApplicationFramework (JSR 296) 曾经试图加进JDK,未果……
如果有 SwingApplicationFramework 的话,也许至少会帮助初学者写出线程基本正确的Swing程序(由于对Swing线程机制的不理解,很多很多的Swing程序线程都是错的,新手开始写Swing程序极少有人把线程写对。留意过一些培训课程,很多“名师”,甚至专讲Swing入门的课程,里面的线程居然也是错的)Oracle 在UI方面的重心还是放在 JavaFX 上了,Swing基本上是处于维护状态。Swing 里的 MVC 也许不是很好的学习的例子,因为可以从不同的层面理解……,而有些层面是 M + VC,其中的 VC 就是一些硬编码的ui类我觉得 Swing 里面最有学习价值的大概是它的单线程机制,因为这种单线程机制是在很多UI框架都通用的知识。有一篇很老的文章今天也没有过时:
https://weblogs.java.net/blog/kgh/archive/2004/10/multithreaded_t.html
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.collections.FXCollections?>
<?import addressbook.*?><Scene xmlns:fx="http://javafx.com/fxml" fx:controller="addressbook.Controller"
stylesheets="addressbook/addressbook.css">
<GridPane styleClass="grid-pane">
<Label id="address-book" text="%addressBook"
GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<TableView fx:id="tableView" tableMenuButtonVisible="true"
GridPane.columnIndex="0" GridPane.rowIndex="1">
<columns>
<TableColumn fx:id="firstNameColumn"
text="%firstName" prefWidth="100">
<cellValueFactory>
<PropertyValueFactory property="firstName"/>
</cellValueFactory>
<cellFactory>
<FormattedTableCellFactory alignment="CENTER"/>
</cellFactory>
</TableColumn>
<TableColumn
text="%lastName" prefWidth="100">
<cellValueFactory>
<PropertyValueFactory property="lastName"/>
</cellValueFactory>
</TableColumn>
<TableColumn
text="%email" prefWidth="210" sortable="false">
<cellValueFactory>
<PropertyValueFactory property="email"/>
</cellValueFactory>
</TableColumn>
</columns>
<Person firstName="Jacob" lastName="Smith"
email="[email protected]"/>
<Person firstName="Isabella" lastName="Johnson"
email="[email protected]"/>
<Person firstName="Ethan" lastName="Williams"
email="[email protected]"/>
<Person firstName="Emma" lastName="Jones"
email="[email protected]"/>
<Person firstName="Michael" lastName="Brown"
email="[email protected]"/>
<sortOrder>
<fx:reference source="firstNameColumn"/>
</sortOrder>
</TableView>
<HBox styleClass="h-box" GridPane.columnIndex="0" GridPane.rowIndex="2">
<TextField fx:id="firstNameField" promptText="%firstName"
prefWidth="90"/>
<TextField fx:id="lastNameField" promptText="%lastName"
prefWidth="90"/>
<TextField fx:id="emailField" promptText="%email"
prefWidth="150"/>
<Button text="%add" onAction="#addPerson"/>
</HBox>
</GridPane>
</Scene>.grid-pane {
-fx-alignment: center;
-fx-hgap: 10;
-fx-vgap: 10;
-fx-padding: 10;
}#address-book {
-fx-font: NORMAL 20 Tahoma;
}.h-box {
-fx-spacing:10;
-fx-alignment: bottom-right;
}# Title of window
title=FXML Address Book# Name of label above the table view
addressBook=Address Book# Name of the first table column
# & Prompt text of text field for the first table column
firstName=First Name# Name of the second table column
# & Prompt text of text field for the second table column
lastName=Last Name# Name of the third table column
# & Prompt text of text field for the third table column
email=Email Address# Name of button for adding rows to table
add=Add# Title of window
title=FXML\u5730\u5740\u7C3F# Name of label above the table view
addressBook=\u5730\u5740\u7C3F# Name of the first table column
# & Prompt text of text field for the first table column
firstName=\u540D\u5B57# Name of the second table column
# & Prompt text of text field for the second table column
lastName=\u59D3# Name of the third table column
# & Prompt text of text field for the third table column
email=\u7535\u5B50\u90AE\u4EF6# Name of button for adding rows to table
add=\u6DFB\u52A0package addressbook;import java.text.Format;import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;public class FormattedTableCellFactory<S, T> implements
Callback<TableColumn<S, T>, TableCell<S, T>> {
private TextAlignment alignment;
private Format format; public TextAlignment getAlignment() {
return alignment;
} public Format getFormat() {
return format;
} public void setAlignment(TextAlignment alignment) {
this.alignment = alignment;
} public void setFormat(Format format) {
this.format = format;
} @Override
public TableCell<S, T> call(TableColumn<S, T> arg0) {
final TableCell<S, T> cell = new TableCell<S, T>() {
@Override
protected void updateItem(T item, boolean empty) {
if (item == getItem()) {
return;
}
super.updateItem(item, empty);
if (item == null) {
setText(null);
setGraphic(null);
} else if (item instanceof Node) {
setText(null);
setGraphic((Node) item);
} else if (format != null) {
setText(format.format(item));
setGraphic(null);
} else {
setText(item.toString());
setGraphic(null);
} /* add a context menu */
addCM(this);
}
};
if (alignment == null) alignment = TextAlignment.LEFT;
cell.setTextAlignment(alignment);
switch (alignment) {
case CENTER:
cell.setAlignment(Pos.CENTER);
break;
case RIGHT:
cell.setAlignment(Pos.CENTER_RIGHT);
break;
default:
cell.setAlignment(Pos.CENTER_LEFT);
}
return cell;
} private MenuItem delete = new MenuItem("Delete");
private ContextMenu contextMenu = new ContextMenu(delete); private void addCM(final TableCell<S, T> cell) {
@SuppressWarnings("rawtypes")
final TableRow row = cell.getTableRow();
delete.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
cell.getTableView().getItems().remove(row.getItem());
}
});
if (row != null) {
if (row.getItem() != null) {
row.setContextMenu(contextMenu);
}
}
}
}package addressbook;import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;/**
* A Bean convention based data model.
*
* @author HAN
*/
public class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty email = new SimpleStringProperty(); public Person() {
this("", "", "");
} public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(email);
} public final String getFirstName() {
return firstName.get();
} public final String getLastName() {
return lastName.get();
} public final String getEmail() {
return email.get();
} public final void setFirstName(String firstName) {
this.firstName.set(firstName);
} public final void setLastName(String lastName) {
this.lastName.set(lastName);
} public final void setEmail(String email) {
this.email.set(email);
} public StringProperty firstNameProperty() {
return firstName;
} public StringProperty lastNameProperty() {
return lastName;
} public StringProperty emailProperty() {
return email;
}
}/**
* An address book application.
*
* @author HAN
*/
package addressbook;package addressbook;import javafx.fxml.FXML;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;public class Controller {
@FXML
private TableView<Person> tableView;
@FXML
private TextField firstNameField;
@FXML
private TextField lastNameField;
@FXML
private TextField emailField; @FXML
private void addPerson() {
tableView.getItems().add(
new Person(firstNameField.getText(), lastNameField.getText(),
emailField.getText()));
firstNameField.clear();
lastNameField.clear();
emailField.clear();
}
}package addressbook;import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;public class Model extends Application {
public static void main(String[] args) {
launch(args);
} @Override
public void start(Stage stage) throws Exception {
Locale locale = getCurrentLocale();
ResourceBundle resources = ResourceBundle
.getBundle("addressbook/addressbook", locale,
Model.class.getClassLoader());
stage.setTitle(resources.getString("title"));
stage.setScene((Scene) FXMLLoader.load(
Model.class.getResource("View.fxml"), resources));
stage.show();
} private Locale getCurrentLocale() {
Map<String, String> namedParams = getParameters().getNamed();
String languageParam = namedParams.get("language");
String countryParam = namedParams.get("country"); Locale locale = Locale.getDefault();
if (languageParam != null && languageParam.trim().length() > 0) {
if (countryParam != null && countryParam.trim().length() > 0) {
locale = new Locale(languageParam.trim(), countryParam.trim());
} else {
locale = new Locale(languageParam.trim());
}
}
return locale;
}
}