【IntelliJ IDEA 2019.2 + jdk8】java fx 绘制界面
加入按钮
参考:https://blog.csdn.net/weixin_41571493/article/details/81415327
通过FX的 helloworld例程,可以发现,第一句语句就是调用fxml文件,
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
由此,可以看出,想要什么样的界面,只需编辑fxml文件就行,
当你点开fxml文件时,会发现有两个视图,一种是Text(左图),一种是 Scene Builder(右图)。
和C#, Android Studio 一样的操作方式,而且操作方式也大同小异。比如,当要画一个按钮时,在 Scene Builder 模式下,把Button拖拽出来即可。
运行的效果如下:
按钮画出来了,那么,怎么把按钮和代码联系起来呢?也就是按一下按钮,就去做相应的事情。
在Scence Builder界面选中按钮,右边就会出现属性栏,点开 Code:Button项,再点开On Action 项,在方框里填入函数名,如下图中填入了“Button_Test_Do”,
再退回 Text模式,就发现多了一个红色的 "Button_Test_Do"的字符串。
把鼠标移到红色字符上,就会提示解决方法:
点击“Create mothod 'Button_Test_Do' in 'Controller' ”就会在 Controller.java 文件里生成代码,如下所示,接下来,我们需要按钮按下的时候做什么,在里面添加代码就行。
在程序里改变控件显示值
下面以在程序里改变button显示值为例。
代码为:
有两个易错点,
易错点1:
是 javafx.scene.control.Button 也不是 Button,如上图红框中所示,这个BUG花费了我半天的时间。当你输入Button时,其实也是会提示两个选项的,这点需要注意了。
易错点2:
在fxml文件里,button的ID是“huiButton”, 但是填进 lookup() 里时,要加上字符“#”, 写成“#huiButton”,如上图红框中所示。
举一反三:
所有控件,包括 Table等等,在程序里实时改变值都是这样的,若想在其它地方也方便地改,可把局部变量改为全局变量。
如 TextArea 写成:
javafx.scene.control.TextArea ta = (javafx.scene.control.TextArea)root.lookup("#huiTextArea");
ta.setText("hui==========================");
改后运行如下:
先画底板
其实,由于上面的画Button步骤之前应该先画一个底板,也就是Container,如果没有先画这个的话,Button就只会在最中间,无法移动到其它位置,控件一旦多了,就会重叠在一起。所以要先画Container.
专业术语: 舞台(Stage),场景(Scene),容器(Container),布局(Layout )和控件(Controls)之间的关系
所以操作步骤是:
第一步先放一个Container, 然后第2步就和C#,Android Studio 一样了,拖拽Control(就是按钮之类的控件)进来。
放控件图如下,图中的是 Containers -- > Pane。
可以在Text模式下精确调节大小,如下:
加类似串口助手的显示区域
如下图,在先有一个Pane的基础上,再选择Controls-->TextArea。就出现了一个显示的区域。
接下来,设定id值。这个id, 在程序里,是用来找到这个控件的。
代码这样写:
运行的结果如下:
改变AreaText字体的方法:
多线程显示内容太多死机,怎么办?
当开了多线程的时候,就会出现以下的情况,整个显示框都卡死了。
原因分析:
因为 m_arg.m_TextArea_main_display.appendText(str_print); 这一句执行需要时间,当要显示的内容越多时,需要的时间越长。当appendText在线程里时,线程切换出去了, 还没执行完,再切回线程时,又执行下一次显示,但是,实际上,上一次的显示任务还没执行完毕呢。这时就会出错了。
解决方法:
知道了原因,解决方法就顺水推舟了,限制相邻两次的最短显示时间即可。
代码及测试代码如下:
static String str_print = new String();
public void Start_Thread(Main.Args arg) throws InterruptedException {
m_arg = arg;
Thread display_thread = new Thread(){
public void run() {
long TickOld = System.currentTimeMillis();
while (true) {
if (str_print.length() > 0 && System.currentTimeMillis() - TickOld > 50 && m_arg.m_TextArea_main_display.isNeedsLayout() == false)
{
TickOld = System.currentTimeMillis();
String tmp = str_print; str_print = "";
m_arg.m_TextArea_main_display.appendText(tmp);
}
try {
Thread.sleep(10); // 延时久一点,拖动界面才不卡。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
display_thread.start();
Thread obd_thread = new Thread(){
public void run(){
run_test();
}
public void run_test(){
while (m_arg == null){}
for (int i=0; i<50000; i++){
try {
Print("------------------------------------------------" + i + "-----------------------------------------------------\n");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(5); // 延时久一点,拖动界面才不卡。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
obd_thread.start();
}
textarea textfield 的区别
extfield只有一行可bai写
textarea是一个区du域,可以有很多行
问题点:javaFX textField onInputMethodTextChanged只能在全角状态下触发
使用了 TextArea 的 "On Input Method Text Change"功能,如下,
但是出现了一个问题,在全角状态下,也就是中文输入法下,可以进入“中断处理函数”,但是,在半角状态下,也就是英文输入法下,无论怎么改变输入框的值,也无法进入“中断处理函数”。
解决方法:找不到办法解决,可能是FX自身的BUG,最好加多一个button来实现这个功能。
加入文件选择控件
先加入一个按钮,如下:
只要一点击,就打开文件选择控件。
按键处理函数里内容如下:
public void ChoseOriginFile_OnAction(ActionEvent actionEvent) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("选择原始文件");
File file = fileChooser.showOpenDialog(Main.m_primaryStage);
Main.m_button.setText(file.getPath());
}
最后一句 Main.m_button.setText(file.getPath()); 是把得到的路径显示在按钮上,效果如下:
如果选择文件夹,则可换成以下代码:
DirectoryChooser directoryChooser=new DirectoryChooser();
File file = directoryChooser.showDialog(Main.m_primaryStage);
String path = file.getPath();//选择的文件夹路径
其中,
Main.m_primaryStage 是全局全静态全局变量(借用C++的说法),代码如下:
public class Main extends Application {
static Stage m_primaryStage;
public void start(Stage primaryStage) throws Exception{
m_primaryStage = primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
这样写完后,虽然实现了选择某个文件的功能,但是,没法记住上一次打开的文件的位置,没次都要从根目录重新打开,那么,有什么好的方法实现记忆住上一次目录打开的位置的。代码改成以下即可:
public void ChoseOriginFile_OnAction(ActionEvent actionEvent) throws IOException {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("选择原始文件");
List<String> list = FileDo.ReadTxt("file choose directory record.ini");
if (list.size() >= 2)fileChooser.setInitialDirectory(new File(list.get(0)));
File file = fileChooser.showOpenDialog(Main.m_primaryStage);
FileDo.WriteTxt("file choose directory record.ini", file.getParent() + "\n" + file.getName());
Main.m_button.setText(file.getName());
}
另外,可在初始化的地主加入:
List<String> list = FileDo.ReadTxt("file choose directory record.ini");
if (list.size() >= 2)m_button.setText(list.get(1));
这的的话,一开机,就会把历史路径显示在按钮上,效果如下:
使用ListView做菜单
1.先加入一个ListView控件。
2.加入初始化代码:
public class Main extends Application {
public javafx.scene.control.ListView m_ListVie_for_menu;
@Override
public void start(Stage primaryStage) throws Exception{
ObservableList<String> items =FXCollections.observableArrayList (
"宝马", "Double", "Suite", "Family App");
m_ListVie_for_menu = (javafx.scene.control.ListView)root.lookup("#ListView_for_menu");
m_ListVie_for_menu.setItems(items);
}
public static void main(String[] args) {
launch(args);
}
}
完成这一步,其实就已经可以看到效果了,如下:
3.使能”可编辑“, 只有打上勾,才可能使用下一步时的那几个“中断处理函数”。
4,使用这个“中断处理函数”,这样,双击就可以进入这个“中断处理函数”。
界面切换
新建一个FXML文件。
FXML文件创建好后,会提示你新建一个源文件,如下:
切换的代码为:
public void OnAction_MessageBox(ActionEvent actionEvent) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("MessageBox.fxml"));
Main.m_primaryStage.setTitle("MessageBox");
Main.m_primaryStage.setScene(new Scene(root, 600, 600));
Main.m_primaryStage.show();
}
其中, Main.m_primaryStage 是“全局变量”, 是这样来的:
public class Main extends Application {
public static Stage m_primaryStage;
@Override
public void start(Stage primaryStage) throws Exception{
m_primaryStage = primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
Label标签的使用
代码更新 Label标签的方法如下:
javafx.scene.control.Label msg_box_lable;
msg_box_lable = (javafx.scene.control.Label)root.lookup("#Label_MsgBox");
if (msg_box_lable != null)msg_box_lable.setText("++++++++++++");
TableView
请参考我在CSDN写的另外一篇文章:《javafx 之 TableView》https://blog.csdn.net/zhuohui307317684/article/details/112470481