加入按钮


通过FX的 helloworld例程,可以发现,第一句语句就是调用fxml文件,

Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));

由此,可以看出,想要什么样的界面,只需编辑fxml文件就行,

 

当你点开fxml文件时,会发现有两个视图,一种是Text(左图),一种是 Scene Builder(右图)。

JAVAFX有界面 javafx漂亮界面_中断处理

JAVAFX有界面 javafx漂亮界面_中断处理_02

和C#, Android Studio 一样的操作方式,而且操作方式也大同小异。比如,当要画一个按钮时,在 Scene Builder 模式下,把Button拖拽出来即可。

运行的效果如下:

JAVAFX有界面 javafx漂亮界面_Text_03

按钮画出来了,那么,怎么把按钮和代码联系起来呢?也就是按一下按钮,就去做相应的事情。

在Scence Builder界面选中按钮,右边就会出现属性栏,点开 Code:Button项,再点开On Action 项,在方框里填入函数名,如下图中填入了“Button_Test_Do”,

JAVAFX有界面 javafx漂亮界面_中断处理_04

再退回 Text模式,就发现多了一个红色的 "Button_Test_Do"的字符串。

JAVAFX有界面 javafx漂亮界面_Text_05

把鼠标移到红色字符上,就会提示解决方法:

JAVAFX有界面 javafx漂亮界面_中断处理_06

点击“Create mothod 'Button_Test_Do' in 'Controller' ”就会在 Controller.java 文件里生成代码,如下所示,接下来,我们需要按钮按下的时候做什么,在里面添加代码就行。

JAVAFX有界面 javafx漂亮界面_中断处理_07

在程序里改变控件显示值

下面以在程序里改变button显示值为例。

代码为:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_08

有两个易错点,

易错点1:

是 javafx.scene.control.Button 也不是 Button,如上图红框中所示,这个BUG花费了我半天的时间。当你输入Button时,其实也是会提示两个选项的,这点需要注意了。

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_09

易错点2:

在fxml文件里,button的ID是“huiButton”, 但是填进 lookup() 里时,要加上字符“#”, 写成“#huiButton”,如上图红框中所示。

举一反三:

所有控件,包括 Table等等,在程序里实时改变值都是这样的,若想在其它地方也方便地改,可把局部变量改为全局变量。

如 TextArea 写成:

javafx.scene.control.TextArea ta = (javafx.scene.control.TextArea)root.lookup("#huiTextArea");
        ta.setText("hui==========================");

 

改后运行如下:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_10

 

先画底板

其实,由于上面的画Button步骤之前应该先画一个底板,也就是Container,如果没有先画这个的话,Button就只会在最中间,无法移动到其它位置,控件一旦多了,就会重叠在一起。所以要先画Container.

专业术语: 舞台(Stage),场景(Scene),容器(Container),布局(Layout )和控件(Controls)之间的关系

JAVAFX有界面 javafx漂亮界面_Text_11

所以操作步骤是:

第一步先放一个Container, 然后第2步就和C#,Android Studio  一样了,拖拽Control(就是按钮之类的控件)进来。

放控件图如下,图中的是 Containers -- > Pane。

JAVAFX有界面 javafx漂亮界面_中断处理_12

可以在Text模式下精确调节大小,如下:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_13

 

加类似串口助手的显示区域

如下图,在先有一个Pane的基础上,再选择Controls-->TextArea。就出现了一个显示的区域。

JAVAFX有界面 javafx漂亮界面_控件_14

接下来,设定id值。这个id, 在程序里,是用来找到这个控件的。

JAVAFX有界面 javafx漂亮界面_控件_15

代码这样写:

JAVAFX有界面 javafx漂亮界面_中断处理_16

运行的结果如下:

JAVAFX有界面 javafx漂亮界面_控件_17

 

改变AreaText字体的方法:

JAVAFX有界面 javafx漂亮界面_Text_18

多线程显示内容太多死机,怎么办?

当开了多线程的时候,就会出现以下的情况,整个显示框都卡死了。

JAVAFX有界面 javafx漂亮界面_Text_19

原因分析:

因为  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"功能,如下,

JAVAFX有界面 javafx漂亮界面_控件_20

但是出现了一个问题,在全角状态下,也就是中文输入法下,可以进入“中断处理函数”,但是,在半角状态下,也就是英文输入法下,无论怎么改变输入框的值,也无法进入“中断处理函数”。

解决方法:找不到办法解决,可能是FX自身的BUG,最好加多一个button来实现这个功能。

 

 

加入文件选择控件

先加入一个按钮,如下:

JAVAFX有界面 javafx漂亮界面_控件_21

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_22

只要一点击,就打开文件选择控件。

按键处理函数里内容如下:

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()); 是把得到的路径显示在按钮上,效果如下:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_23

 

如果选择文件夹,则可换成以下代码:

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));

这的的话,一开机,就会把历史路径显示在按钮上,效果如下:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_24

使用ListView做菜单

1.先加入一个ListView控件。

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_25

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);
    }
}

完成这一步,其实就已经可以看到效果了,如下:

JAVAFX有界面 javafx漂亮界面_中断处理_26

3.使能”可编辑“, 只有打上勾,才可能使用下一步时的那几个“中断处理函数”。

JAVAFX有界面 javafx漂亮界面_Text_27

4,使用这个“中断处理函数”,这样,双击就可以进入这个“中断处理函数”。

JAVAFX有界面 javafx漂亮界面_Text_28

 

界面切换

新建一个FXML文件。

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_29

FXML文件创建好后,会提示你新建一个源文件,如下:

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_30

切换的代码为:

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标签的使用

JAVAFX有界面 javafx漂亮界面_JAVAFX有界面_31

代码更新 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("++++++++++++");